Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom types in Navigation parameters in v3

Tags:

mvvmcross

In v3 if I wanted to pass two objects to another viewmodel:

public class Dog
{

}

public class Cat
{

}

var dog = new Dog();
var cat = new Cat();

ShowViewModel<SomeViewModel>(new {Dog = dog, Cat = cat });

public class SomeViewModel
{
  Init(Dog dog, Cat cat)
  {
  }
}

As far as I can tell that won't work because the types aren't recognized and can't be stuck in a dictionary. If I wanted to have these serialized as json, passed to the view model, and deserialized as Init parameters, would I implement IExtraParser? And if that is correct, how do I go about adding the implementations to the ExtraParsers dictionary?

update:

This seems to do it:

var foo = Mvx.Resolve<IMvxFillableStringToTypeParser>();
foo.ExtraParsers.Add(new MyParser());
like image 317
Derek Beattie Avatar asked May 13 '13 14:05

Derek Beattie


1 Answers

The default navigation mechanism in MvvmCross is deliberately lightweight.

It is really there to allow you to pass just one simple, serializable object - e.g.

public class DogNav
{
   public int Id {get;set;}
   public string Caption {get;set;}
}

// received in:
public class DogViewModel : MvxViewModel
{
   public void Init(DogNav dogNav)
   {
   }
}

With this setup, if a navigation is triggered like:

// navigation
ShowViewModel<DogViewModel>(new DogNav() { Id=12, Caption="Good boy" });

then the underlying system will transport the values from that DogNav object - possibly using Uris, Intents or other serialization techniques - to the new DogViewModel and will then ensure Init is called with the correct values.

Because of the serialization, it's important:

  • not to pass big objects (Uris on WindowsPhone can break above a few hundred characters)
  • not to expect the same object instance to arrive - i.e. if you are using database-backed or stateful objects, then it's best to pass some kind of lookup key rather than the objects themselves.
  • not to expect that only one ViewModel will receive the message - on some operating systems, it may be that the user goes back and forth many, many times between apps causing many Views and ViewModels to be created.
  • not to expect that a ViewModel that receives the message is in the same process and memory space as the ViewModel that sent the request - the same may actually be received days later after a tombstoning event.

If you do want to pass multiple objects via navigation, then I think you can do this using code like:

public class CatNav
{
   public int CatId {get;set;}
   public string CatCaption {get;set;}
}

public class DogNav
{
   public int DogId {get;set;}
   public string DogCaption {get;set;}
}

// received in:
public class CatAndDogViewModel : MvxViewModel
{
   public void Init(DogNav dogNav)
   {
   }

   public void Init(CatNav catNav)
   {
   }
}

In this case you could navigate using:

var catNav = new CatNav() { CatId =12, CatCaption="Meow" };
var dogNav = new DogNav() { DogId =12, DogCaption="Woof" };
var bundle = new MvxBundle();
bundle.Write(catNav);
bundle.Write(dogNav);
ShowViewModel<CatAndDogViewModel>(bundle);

I think this would work...

However... please be aware that the serialization is very simple - so if CatNav and DogNav were to share a property name, then this would lead to problems - you'd end up with some Cags and Dots

Because of the Cag and Dot problem I don't recommend this approach...


If you do need more complex transitions in your apps, then one route is to:

UPDATE - see Passing complex navigation parameters with MvvmCross ShowViewModel

1. Add the Json Plugin (or any Json serializer) and change your Setup.cs code to create a MvxJsonNavigationSerializer - overriding CreateNavigationSerializer

     protected override IMvxNavigationSerializer CreateNavigationSerializer()
     {
         return new MvxJsonNavigationSerializer();
     }
  1. Use a composite object in navigation like:

    public class DogAndCatNav
    {
       public DogNav DogNav {get;set;}
       public CatNav CatNav {get;set;}
    }
    
  2. This would be received by:

    public void Init(DogAndCatNav dogAndCatNav)
    {
    }
    

But note that this technique does need a more powerful serialization engine - such as Json.


Overall... even after writing all this... I'd recommend you pass as little data as possible in your navigations!

like image 158
Stuart Avatar answered Nov 07 '22 03:11

Stuart