Misuses Of MessagingCenter

MessagingCenter is a global event messaging system designed to allow two separate entities communicate without knowing anything about each other, besides a simple messaging contract. This architectural style of system works well for larger systems such as Amazon who use a similar event-sourced approach of micro services to implement a recommendation system, payment system, shipping system etc. These systems are distinctly separate and have teams working on each.

Mobile application development however is dealing with a much smaller system in most circumstances, with a single user interacting with a single page. To implement MessagingCenter in a mobile application is either a complete over architecture or its not being done properly.

Timing & State Issues

Timing issues are one of the largest concerns I have seen with MessagingCenter. If you load a page and OnAppearing is called and you have the possibility of a subscription to the MessagingCenter, how would you know if the OnAppearing got called first or the MessagingCenter. State validity is the main concern here as with all the following scenarios. MVVM is assumed in a few patterns.

ViewModel to Page

If you have a page binding to a ViewModel, the binding engine is there to relay information back and forth between the two entities. If you add MessagingCenter, then you add an additional path for the data to flow. If accessing a method on a control is the main concern, then expand the control to add Bindable Properties.

vmtopage

Page to Page

States should be managed by the Model, through the ViewModel, through the binding engine to the page. Jumping across pages can lead to immense state issues when your binding engine is competing with your subscriptions to modify page elements.

pagetopage

ViewModel to ViewModel

VM to VM communication is a common example of MessagingCenter usage. Communicating with an inactive VM boudn to a page that most likely isn’t showing yet is a pathway to timing and state issues.

To push data from one VM to another as you move pages in your application you can provide these mechanisms in your Navigation Service. The Navigation Service will already have a reference to your Page and ViewModel for binding and pushing purposes, why not just add a parameter to the Push command and pass that through when you have a reference to your new ViewModel.

// In your current ViewModel
await _navigationService.Push(args);

// In Navigation Service
myPage.BindingContext = theViewModel;
await _navigationPage.PushAsync();
theViewModel.OnNavigated(args);

 

vmtovm

Model to Model or Service

Models and services can talk to each other via constructor injection. If your model has a dependency on another model, then it should list it, as with services.

modeltomodel

If you are now thinking that your Model’s have a hard dependency, this is true, but why shouldn’t they. It is obvious one depends upon the other, the MessagingCenter doesn’t alleviate the dependency, just makes it harder or you to track. You can go one step further and split the entity.

splitmodel

It is important that your models or services all implement an appropriate interface. With this approach you can restrict what a class does call of another and allow other classes greater API access.

Following Dependencies Not Events

Debugging code with events, especially ones tied together by magic strings, as is the case in most MessagingCenter implementations, becomes a nightmare. Following dependencies give greater assurance that operations are performed in sequence and that you can trace the code back without setting up debugging break points everywhere to trap an event.

Summary

Currently my list of situations suitable for MessagingCenter sits at zero. I don’t use MessagingCenter at all in any of my code. I know the Xamarin Forms framework uses but I never manually implement it my projects. In my opinion it seems like a quick workaround to not tie entities together because the solution was never architected properly at the beginning. If you are depending on another entity, then associate with a contract for that entity. Contact me on email or Twitter if you do have some good valid use cases for MessagingCenter, I would be very interested to hear them.

Microsoft MVP | Xamarin Certified Developer |
Exrin Creator | Xamarin Forms Developer | Melbourne, Australia

Related Posts

20 Comments

  1. Seth

    I’ve used it mainly when I’m deep in the navigation stack and I need to notify something higher up that something changed. A specific instance I had was my app was a Master-detail application with counts next to the menu items. Anytime something changed in the app, I would just send a message that the menu list needed to refresh.

    Do you have any recommendations in that scenario?

    1. Adam Pedley

      Thanks for listing out your scenario. A possible other solution would be to look at having an class with the counts in them, something that holds the these states. This entity/class is then injected in the pages that update it, and also the Master page. Then when one updates the counts, binding will reflect that across anything that is bound to those properties.

  2. erwin lee

    Imagine having a list of bookings on 1 page, the list of bookings is cached so you don’t have to to back to the server every time. The only time you will refresh this list is when user explicitly requests or when user makes a new booking. So, the create booking view model, will send a notification via messaging center to the booking list view model so it can refresh itself and include the new booking to its list.

    What do you think?

    1. Adam Pedley

      My approach to that situation would be to have the cached list of the bookings in a BookingModel that both the ViewModel’s have access to. Then when one ViewModel updates the BookingModel’s list of bookings, the other ViewModel has immediate access to them when needed. The BookingModel is a single instance shared across both ViewModels.

      This alleviates the issues of keeping 2 states in 2 different ViewModels and dealing with an additional message flow.

  3. Rob

    I don’t like Messenger either.
    Many people use it because it solves relationing very easy. The usual answer is “it’s good because the systems are not coupled to each other, it’s perfect”.
    As bad as it may sound I think coupling is good, when you look at the code you can clearly see and track the depedencies.
    In the other hand, someone could wrap a service around the Messenger, and have the service DI injected in view-models 🙂

  4. Ahmad Elmadi

    In my case I am using the messagingCenter to send messages from the platfrom project .
    I am working with TV apps , which is not natively supported in XF. So I basically in the android project listen to keystrokes , and when a user press something on the remote controls it triggers “OnKeyDown” and “OnKeyUp” events. So when that happens I send a message to XF components using MessagingCenter.
    Do you have an alternative way to do so ?

    I have a question for you , What do you think of a page listening to an event from its ViewModel? So the page can DisplayAlert() ? do you have another way to do so ?

    1. Adam Pedley

      While I don’t have the specifics of your project, the keypress is either part of a visual element or a service in Android. If its a visual element I would create a custom renderer and pass the information back through the control. If its a service, you can simply dependency injection your service to be called or listened from in your portable library.

      A quick way is DisplayAlert can be called by Application.Current.MainPage.DisplayAlert from the ViewModel, however I would recommend you look at your MVVM Helper Library that would most likely have implemented that better for you.

      1. Ahmad Elmadi

        Well it is a method that can be overrriden from MainActivity , just like onCreate and OnStart. Don’t know where do you put that as a category .

      2. Adam Pedley

        You would create a class, that implements an interface and create a new instance of it in MainActivity. This class will have properties that are Action’s.

        You can pass this class down via the new App() or put in in your DI framework.

        Then assign those Actions in your portable library.

        In MainActivity you can then call the Actions with OnKeyPressed?.Invoke(); This will call straight into your Portable without any need for MessagingCenter and gives you a direct, straight forward debugging path and code execution.

  5. Hiral

    I’ve used it in following instance.

    Toolbar item on a content page inside a navigation page.
    Tollbar item needs to hide/show based on a property inside a ViewModel bound to the page

    Is there any workaround to that?

    1. Adam Pedley

      Since the property isn’t just available to the ViewModel, it could be extracted to its own class. This class can then be injected into the service that handles the NavigationPage and the ViewModel.

      This allows you to see how they reference each other and not have a global event flying around your app. Basically its having a shared class/entity between them, and its similar to the MessagingCenter approach but more tightly controlled.

  6. Antonio

    Hi, first of all my congratulations for the post, it’s good your analysis.

    My case is this:

    1) I have ViewModel call intranetViewModel where are the binding of the page intranet.xaml

    2) I have a class called service, which connects to webservice (asmx) and brings the data to display in view

    public class Service{
    public void GetPost(){
    intranetServoce.PostAsync();
    intranetServoce.PostAsyncCompleted += (object sender, PostAsyncCompletedEventArgs e) =>
    {
    data= e.Result;
    };

    }
    }

    3) From the viewmodel called the method to bring the data

    Service = services= new Service();
    services.GetPost();

    4) When the service responds, I have to use that data and load a viewmodel list so that it is shown in lisview

    The only mechanism I found to do this was the MessagingCenter. Do you think it can be done differently?

    1. Adam Pedley

      To trigger the download, I imagine your ViewModel, would call your Model, that would then call your Service?

      In that case your ViewModel has a direct line of reference to the service, and should just use the returned result.

      1. Antonio

        Hi, thank you for you answer.

        That is the problem, as you should know the service call is asynchronous and in asmx does not implement async and await. So I can not implement a return.

        The viewmodel calls the method in the service class, and continues its execution, does not wait for response.

        Then the way I found for the service to notify and send the response data to viewmodel, was using MessagingCenter

        1. Adam Pedley

          I would then wrap around the function and make it manually wait for the response, using something like a ManualResetEvent.

          e.g.

          var reset = new ManualResetEvent(false);

          // Make call to asmx

          await Task.Run(() => reset.WaitOne() );

          // Return the result

          The result will come from another variable, where ever the return result comes back from the webservice, do reset.Set(); and store the value.

          Otherwise, it would be just using a event chain back, in which case its almost no different than the MessagingCenter.

          But again, this might be overkill if its just a simple application.

              1. Antonio

                You know, I found another problem, and I sent a variable by reference to handle the issue of errors, but in this process of encapsulating with async and await you can not use variable for that type then choose to create a standard object that goes To return all services

                        Public class AnswerService
                        {

                            Public bool EsCorrecto {get; set; }
                            Public string Error {get; set; }
                            Public int Code {get; set; }
                            Public string Exception {get; set; }
                            Public Object Result {get; set; }

                        }

                It is assumed that the result should be the data that before I returned the function (List, string, bool, Object etc)

                When I call the service and the result variable is a List for example gives this error

                Error generating XML document. —> The System.Collections.Generic.List` type can not be used in this context.

                Try with an array and neither, I do not know if you can do this in this asmx schema because I know that internally there is a mapping of the service q does .net when generating the proxy in the client and object is generic.

                How could I solve this or what alternative could I use to return both the data and the object of error?

Leave A Comment?