MVVM Cross Basics – Passing Complex Parameters During Navigation

Having covered basic navigation, I found that I needed to pass my game state from view-model to view-model. I initially thought that I could simply do this as follows:

    private void CallVM2()
    {
        MyObj newObj = new MyObj();
        IMyService myService = new MyService();

		Dictionary<string, object> p = new Dictionary<string, object>()
        {
            {"MyObj", newObj},
            {"MyService", myService}
        };
		ShowViewModel<ViewModel2>(p);
    }

The code for ViewModel2:

    public void Init(Dictionary<string, object> p)
    {
    }

Anyway, it turns out you can’t. Init does get fired, but if you pass anything more complex than a string, it just bins the parameter.

The answer appears to be to create a class and to serialise it using JSON.NET:

http://stackoverflow.com/questions/19058173/passing-complex-navigation-parameters-with-mvvmcross-showviewmodel

After implementing this suggestion, I ended up with something like this:

    public abstract class BaseViewModel : MvxViewModel
    {
        private const string ParameterName = "parameter";

        public BaseViewModel()
        {
        }

        protected void ShowViewModel<TViewModel>(object parameter) where TViewModel : IMvxViewModel
        {
            var text = Mvx.Resolve<IMvxJsonConverter>().SerializeObject(parameter);
            base.ShowViewModel<TViewModel>(text);
        }

        public void Init(string parameter)
        {
            if (parameter == null || parameter.Length == 0) return;

            IMvxJsonConverter converter = Mvx.Resolve<IMvxJsonConverter>();
            NavigationParameter deserialized = converter.DeserializeObject<NavigationParameter>(parameter);
            RealInit(deserialized);
            
        }
    }

If you don’t register the converter in the IoC container (as I initially didn’t), then you’ll get this error:

A first chance exception of type ‘Cirrious.CrossCore.Exceptions.MvxIoCResolveException’ occurred in Cirrious.CrossCore.DLL

Additional information: Failed to resolve type Cirrious.CrossCore.Platform.IMvxJsonConverter

The fix:

    public abstract class BaseViewModel : MvxViewModel
    {
        private const string ParameterName = "parameter";

        public BaseViewModel()
        {
            Mvx.RegisterType<IMvxJsonConverter, MvxJsonConverter>();
        }

Now, if you override the `RealInit` method, you’ll see that the parameters are, indeed, available. However, I had a further problem; this time being with JSON.NET. As you can see from the above structure, it’s a dictionary of objects. So, when running this, it will certainly pass through the object, but it’ll just be the serialised string.

And…?

I’m pretty sure that I could get around this using a combination of generics and a custom Javascript serialisation library, but I’ve got a game to write, so I’m going to stick with declaring the Navigation parameter as follows:

   public class NavigationParameter
    {
        public MyObject ObjectParameter { get; set; }
        public MyService ServiceParameter { get; set; } 
    }

It’s worth bearing in mind that you can’t use interfaces either in the parameters; JSON.NET needs a concrete class.

4 thoughts on “MVVM Cross Basics – Passing Complex Parameters During Navigation

  1. Tymur

    but you still can avoid serialization at all:

    1. Declare a simple class
    class NavigationParameter
    {
    public object Value { get; set; }
    }

    and register it in IoC as singleton.

    2. Pass any argument
    Dictionary<string, object> p = new Dictionary<string, object>()
    {
    {“MyObj”, newObj},
    {“MyService”, myService}
    };

    var arg = Mvx.Resolve<NavigationParameter>();
    arg.Value = p;

    ShowViewModel<ViewModel2>();

    3. Access the argument on ViewModel2 side:
    void Init()
    {
    var arg = Mvx.Resolve<NavigationParameter>();
    var p = arg.Value as Dictionary<string, object>;
    }

    Reply
  2. pcmichaels

    This approach will certainly work. The obvious downside is that you potentially end up registering an expensive class in memory that will remain there, even if the user never needs to load ViewModel2.

    Reply
    1. Tymur

      We are talking about navigation, so the user NEEDS to load ViewModel2. And constructing an object is obviously much cheaper than construction + serialization

      Reply
      1. pcmichaels

        Yes, I completely agree. My point was just that despite serialization being expensive, there are times when this may be preferably to maintaining a large object in memory.

        Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.