Saturday, January 25, 2014

Type-safe ViewModel to ViewModel navigation in MvvmCross


In MvvmCross you can navigate between view-model's as described in the Wiki:
https://github.com/MvvmCross/MvvmCross/wiki/ViewModel--to-ViewModel-navigation

It's good however to use a simple type-safety mechanism.
Suppose we have a ProductViewModel which expects two arguments for initialization:

public class ProductViewModel : MvxViewModel
{
     public void Init(int productId, int clientId)
     {
          ....
     }
}

With a type-safe mechanism, instead of writing:

ShowViewModel<ProductViewModel>(new { productId = pid, clientId = cid });

we can write:

NavigationHelper.ShowProduct(pid, cid);

where NavigationHelper is a simple utility class:

using Cirrious.CrossCore;
using Cirrious.MvvmCross.ViewModels;
using Cirrious.MvvmCross.Views;
using MyApp.Core.ViewModels;
using Cirrious.MvvmCross.Platform;

namespace MyApp.Core.Common
{
    public static class NavigationHelper
    {
        public static void ShowProduct(int productId, int clientId)
        {
            ShowViewModel<ProductViewModel>(new { productId = productId, clientId = clientId });
        }

        static void ShowViewModel<T>(object parameter) where T : IMvxViewModel
        {
            var viewDispatcher = Mvx.Resolve<IMvxViewDispatcher>();
            var request = MvxViewModelRequest.GetDefaultRequest(typeof(T));
            request.ParameterValues = ((object)parameter).ToSimplePropertyDictionary();
            viewDispatcher.ShowViewModel(request);
        }
    }
}

using Cirrious.MvvmCross.Platform; namespace statement is important because it contains the ToSimplePropertyDictionary() extension method implemented by MvvmCross.

Furthermore, instead of using the NavigationHelper class, we can move the ShowViewModel method to a ViewModelBase class:

public class ViewModelBase : MvxViewModel
{
       protected static void ShowViewModel<T>(dynamic parameter) where T : IMvxViewModel        
       {            
           var viewDispatcher = Mvx.Resolve<IMvxViewDispatcher>();            
           var request = MvxViewModelRequest.GetDefaultRequest(typeof(T));            
           request.ParameterValues = ((object)parameter).ToSimplePropertyDictionary();            
           viewDispatcher.ShowViewModel(request);        
       }
}

public class ProductViewModel : ViewModelBase
{
    public static Show(int productId, int clientId)
    {
        ShowViewModel<ProductViewModel>(new { productId = productId, clientId = clientId });
    }

    public void Init(int productId, int clientId)
    {
        ...
    }
}

and we can now write:

ProductViewModel.Show(pid, cid);

Having the Show method near the Init method in the ViewModel class, makes it a bit more easier to maintain the parameters.

No comments: