5
votes

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());
1
How to receive MvxBundle object on next ViewModel ? I write like this: public void Init(MvxBundle objBundle) { var = objBundle; } but thier is nothing in objBunlde. It shows NULLAjay Sharma

1 Answers

11
votes

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!