Search code examples
c#androidmvvmcross

MVVMCross Messenger Plugin Android


Reffering to N=9 what I would like to do is in place of ILocationService I have my own INavigationService and a Navigation Service class.

  public class NavigationService :INavigationService
{
    private readonly IMvxMessenger _navigator;

    public NavigationService(IMvxMessenger navigator)
    {
        _navigator = navigator;
    }

    public void OnNavigation(PurchasesDataEntryViewModel vm)
    {
        var navigationMessage = new NavigationMessage(this,vm);
        _navigator.Publish(navigationMessage);
    }

}

And this is my Messenger class:

   public class NavigationMessage : MvxMessage
{
    public string ShopID { private set; get; }
    public int TotalStock { private set; get; }
    public int TotalPurchases { private set; get; }
    public int Stock1 { private set; get; }
    public int Stock2 { private set; get; }
    public int Stock3 { private set; get; }
    public int Purch1 { private set; get; }
    public int Purch2 { private set; get; }
    public int Purch3 { private set; get; }
    public string Name { private set; get; }
    public string CPrice { private set; get; }
    public int CSales { private set; get; }
    public string BrandID { private set; get; }
    public string CatID { private set; get; }
    public int LadgePur { private set; get; }
    public decimal LPrice { private set; get; }
    public int LPurch { private set; get; }
    public int LSales { private set; get; }
    public int LStock { private set; get; }
    public int LStock1 { private set; get; }
    public string MeasureID { private set; get; }


    public NavigationMessage(object sender, PurchasesDataEntryViewModel vm)
        : base(sender)
    {
        ShopID = vm.ShopID;
        TotalStock = vm.TotalStock;
        TotalPurchases = vm.TotalPurchases;
        Stock1 = vm.Stock1;
        Stock2 = vm.Stock2;
        Stock3 = vm.Stock3;
        //Purch1 = vm.Purch1;
        //Purch2 = vm.Purch2;
        //Purch3 = vm.Purch3;
        Name = vm.Name;
        CPrice = vm.CPrice;
      //  CSales = vm.CSales;
        BrandID = vm.BrandID;
        CatID = vm.CatID;
        LadgePur = vm.LadgePur;
        LPrice = vm.LPrice;
        LPurch = vm.LPurch;
        LSales = vm.LSales;
        LStock = vm.LStock;
        LStock1 = vm.LStock1;
        MeasureID = vm.MeasureID;
    }

What I want to achieve is to send the above values to my subscriber PurchasesDataEntryViewModel

 private readonly IDataService _dataService;
    private readonly MvxSubscriptionToken _token;

    public PurchasesDataEntryViewModel(IDataService dataService,INavigationService service, IMvxMessenger navigator)
    {
        _dataService = dataService;
        _token = navigator.Subscribe<NavigationMessage>(OnNavigationMessage);
    }

    private void OnNavigationMessage(NavigationMessage navigationMessage)
    {
        ShopID = navigationMessage.ShopID;
        .
        .
        .

    }

}

I cannot make it to work. I need to understand the interaction and lifecycle of Publish/Subscribe. How do the two viewmodels will understand how to communicate. I need somehow to tell my Messenger service that I want to send parameters from ViewModel A to ViewModel B through the messenger class. This is the first time I use the plugin so forgive me for the stupid questions.


Solution

  • The use of the Messenger class Publish and Subscribe methods is introduced in https://github.com/MvvmCross/MvvmCross/wiki/MvvmCross-plugins#Messenger

    Your use of the calls in the code in the question looks good to me - any message published by your navigation service should be received by all existing PurchasesDataEntryViewModels


    Update After your comment about:

    when I publish the message I'am expecting my debugger to fire the constructor of the PurchasesDataEntryViewModel class

    This is incorrect.

    Any messenger (MvvmCross or not) can only pass messages between existing objects - it can't create new listeners dynamically.

    If you do want a new object created in response to a message, then you will need to subscribe to that message type from a Factory object - and that Factory object will then need to create the new objects in its message handler.

    private readonly MvxSubscriptionToken _token;
    
    public Factory(IMvxMessenger navigator)
    {
        _token = navigator.Subscribe<NavigationMessage>(OnNavigationMessage);
    }
    
    private void OnNavigationMessage(NavigationMessage navigationMessage)
    {
        switch (navigationMessage.NavType)
        {
             case NavType.One:
                 var newOne = new One(navigationMessage.Args);
                 // use newOne;
                 // ...
    
             // ...
        }
    }
    

    For UI navigation, you will need to make sure that whatever Factory objects you write will also create the View as well as the ViewModel.

    In practice, if you want to write your own navigation service, then you will need to write a navigation service specific to each platform you support - as each platform has different navigation techniques and lifecycles (Android has Intents, WP has Uris, iOS has code-based transitions, etc).

    Since MvvmCross already provides a cross-platform navigation service, you may find it easier to use this and to adapt it using a custom presenter - this is discussed in: