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. 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>;
    }

  2. 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.

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

      1. 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s