Implementing MVVM Message Routing with XAML

1/20/2011 8:51:18 AM

Watch the Channel 9 video here

Download Source Code

If you have worked with MVVM for any period of time, you will find yourself in a situation where you have multiple ViewModels being used on a single page of your application.  Regardless of why you have multiple ViewModels, the challenge of coordinating activity between them is the same: how do I get a ViewModel A to react to some action taken in ViewModel B.  The classic example of this would be you have a ViewModel called CustomerListViewModel that is responsible for working with a View to search for and list customers from a database or web service.  When the user selects a customer, you want another ViewModel, let’s call this one OrdersViewModel, bot be notified and as a result, display all of the orders associated with a the selected customer.

There are lots of approaches to doing this.  PRISM uses the EventAggregator.  For a lot of apps, I lean towards a simpler implementation, similar to the one described by Brent Edwards here.  A lot of times, once you start investigating using some kind of messaging solution, the problem of wiring up the “message bus” with the ViewModels will raise it’s somewhat ugly head.  A lot of solutions rely on either a DI/IoC solution or maybe on some application-wide “service” to provide a messaging capability.  The problem with first approach is that you have to understand DI/IoC (not a bad thing necessarily) and you have to pick an IoC (lots of choices and if you are doing nScreen not all of them work everywhere so you have to be prudent with your choices).  The second solution can be tricky since you have to worry about how the ViewModels subscribe and publish with the service, and more importantly, that ViewModels unsubscribe when they no longer need the service.

When I was looking at this problem for the project I am working on, I had a few things I took into consideration and by doing so I was led to the solution I am about to show you.  First, I was building a multi-screen solution, or nScreen.  This meant that my app would be running in the browser, out of the browser, and on Windows Phone 7.  This necessitated that I look at my ViewModels as potentially the only ViewModel on a given page or I could have multiple ViewModels on a page.  This meant that from one implementation to another, a given ViewModel may or may not need to publish/subscribe to the message bus. Secondly, because I was building for nScreen, and I wanted anyone to be able to use what I was building as a template for their own nScreen solutions, I really didn’t want to dictate going the DI/IoC route if I didn’t have to.  Lastly, I wanted to make using the message bus as easy as possible, especially for people that may be working with the

In most cases, I feel that when dealing with multiple ViewModels on a single “page”, the message bus only needs to exist for the lifetime of that page and that having an application-wide service is not needed.  With that in mind, here is the approach I used for my project.

First, I used the same IMessageBus solution that Brent talks about in his blog.  As with most MVVM frameworks, I had implemented a BaseViewModel class that was the foundation for each of my ViewModels.  The first thing I did was add a MessageBus property to my BaseViewModel class

private IMessageBus _messageBus;
public IMessageBus MessageBus
{
    get { return _messageBus; }
    set
    {
        if (_messageBus != null)
           Unsubscribe();
        _messageBus = value;
           Subscribe();
    }
}

Now you are probably asking why am adding the MessageBus as a Property.  I don’t want to have to write code in my code-behind to wire up a message bus object for a given page to the various ViewModels, either directly or using some other mechanism like an IoC Container.  This enables me to use the property to configure message passing on a page using something similar to Property-based Dependency Injection.  So how do I do that?  Let’s start by looking at a sample MainPage.xaml.

<UserControl>
    <Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
    </Grid>
        <Grid x:Name="CustomerGrid">
            <Grid.DataContext>
                <MessageBusDemo_ViewModels:CustomerListViewModel/>
            </Grid.DataContext>
        </Grid>
        <Grid x:Name="OrdersGrid">
            <Grid.DataContext>
                <MessageBusDemo_ViewModels:OrdersViewModel/>
            </Grid.DataContext>
        </Grid>
</UserControl>

I have two Grids on the page, each with their DataContext set to a different ViewModel.  I would like the CustomerListViewModel to publish messages to the MessageBus whenever a customer is selected, and have the OrdersViewModel subscribe to those messages so it can display orders for the selected customer.  To make this happen, I need to have an instance of the MessageBus available on this page that both of the ViewModels are aware of.  I have a couple of different options for getting the MessageBus created.  In Visual Studio, I can just add an object resource to the page’s Resource collection as shown below:

<UserControl.Resources>
     <MessageBusDemo_Core:MessageBus x:Key="MessageBus"/>
</UserControl.Resources>

In Visual Studio, you need to do this by hand in the XAML.  If you are using Expression Blend, you can also do it by hand, or you can use the Data tab and select Create Object Data Source and select the MessageBus class from the Create Object Data Source dialog.  I then like to go in and remover the  d:IsDataSource="True" attribute from the resulting XAML since the MessageBus object is really not a data source and it makes the data binding we are about to do a bit more natural.  That’s just my opinion.

Once I have added the the MessageBus to my XAML, I can now wire up the various ViewModels to the MessageBus using data binding.  In Visual Studio, this is again all done by hand editing the XAML.  But if I am using Expression Blend, this all becomes a wonderfully easy point and click exercise.  For each Grid, use the Property editor to select the DataContext property and create a New data context and pick the appropriate ViewModel class.  Then, use the drop arrow to reveal the properties on the ViewModel.  Select the MessageBus property and using the Advanced Options square, choose Local Resource and pick the MessageBus.  Bang!  You have now wired up the ViewModel to the MessageBus.  Check out the Channel 9 video I recorded that walks you through this entire entire article to see how it all works.

From there, your ViewModels can now call MessageBus.Publish or MessageBus.Subscribe as needed.  Because the MessageBus property is set post-construction, you will not be able to setup your subscriptions when the object is instantiated. 

You can then use the Subscribe method to setup all of the required subscriptions when a MessageBus is available to your ViewModel.  On the BaseViewModel, just set up some virtual methods that you can override in each of your own derived ViewModel classes.  That is why the property definition on the BaseViewModel includes calls to a Subscribe() and UnSubscribe() method.  There are virtual methods on the BaseViewModel…

public virtual void UnSubscribe() { }
public virtual void Subscribe() { }

In your derived ViewModels, all you need to do is override these two methods so that your ViewModels will automatically Subscribe/Unsubscribe with the MessageBus.  Here is an example of how it is down in the OrdersListViewModel in the demo application

protected override void Subscribe()
{
    MessageBus.Subscribe<Customer>(GetOrdersForCustomer);
}
protected override void Unsubscribe()
{
    MessageBus.Unsubscribe<Customer>(GetOrdersForCustomer);
}

I’m noodling on a way provide an interactive design experience for the MessageBus using XAML, allowing you to configure ViewModel’s subscriptions in XAML as well.  I have a few ideas, but need to explore them in more detail at a later time.

Tags:

Powered by BlogEngine.NET 1.6.0.0
Theme by Mads Kristensen

About the author

Jeff Brand Jeff Brand

This is the personal web site of Jeff Brand, self-proclaimed .NET Sex Symbol and All-Around Good guy. Content from my presentations, blog, and links to other useful .NET information can all be found here.

E-mail me Send mail


Calendar

<<  May 2012  >>
MoTuWeThFrSaSu
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar

My Twitter Updates

XBOX
Live

Recent comments

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2012

Sign in