Presenters in MvvmCross: Using Presentation Values

As shown in my last post, a MvxViewModelRequest contains a dictionary named PresentationValues that can be very useful in passing around data that your presenter might find useful. Let's say you that in your view model you know that when you request to show a view model you know that you want to clear the app's back stack before showing it, such as after a login operation so that the login screen is no longer in the stack.

All overloads of ShowViewModel() in MvvmCross contain an optional IMvxBundle parameter named presentationBundle. It's easy to create a bundle from a dictionary and then pass that into the show request:

var presentationBundle = new MvxBundle(new Dictionary<string, string> { { "NavigationMode", "ClearStack" } });

ShowViewModel<MyViewModelType>(presentationBundle: presentationBundle);

When your platform's presenter gets that request, the values you passed in with the presentation bundle will be available in the PresentationValues property described earlier. With that in place, let's implement the clear operation on both iOS and Android.

iOS

For this example I'm going to assume the presenter inherits from the standard MvxTouchViewPresenter class provided in MvvmCross, which manages a UINavigationController stored in a property named MasterNavigationController. All our presenter needs to do is detect the hint we sent in the request and react accordingly:

public override void Show(MvxViewModelRequest request)
{
	if (request.PresentationValues != null)
	{
		if (request.PresentationValues.ContainsKey("NavigationMode") && request.PresentationValues["NavigationMode"] == "ClearStack")
			MasterNavigationController.PopToRootViewController(false);
	}

	base.Show(request);
}

I'm using magic strings here to keep things simple, but you could use constants/enums/whatever works for your application if you want to formalize things a bit more. The false sent in to PopToRootViewController() says not to animate so that it happens immediately. You can easily get yourself into trouble with UINavigationController if you have competing navigations, so definitely be careful there. I'll dig into that topic further in a future post.

Android

Now let's look at Android. I'm going to assume a presenter that's using fragments for all views and has a FragmentManager field it uses to manage them. In a future post I'll talk in more detail on how to implement this model in Android, but that's a bit off topic here. With that aside, the Android implementation ends up looking pretty similar to iOS:

public override void Show(MvxViewModelRequest request)
{
    if (vmRequest.PresentationValues != null)
    {
        if (request.PresentationValues.ContainsKey("NavigationMode") && request.PresentationValues["NavigationMode"] == "ClearStack")
            _fragmentManager.PopBackStackImmediate(null, PopBackStackFlags.Inclusive);
    }

    // ...
}

This is just one thing you can do with presentation values, so it's really up to you and what makes sense in your apps. If you have some knowledge in your view models that are of use to the presenter during a request, these values provide an easy way to pass that knowledge along with it.