In a previous post I blogged on various ways to tackle the problem of showing dialogs in an MVVM application. There I advocated using events as a communication mechanism. The ViewModel fires an event; the View can subscribe to the event and respond in a way that interacts with the user, which could be by displaying a dialog. It is important to avoid showing dialogs or other visuals directly from the ViewModel in order to maintain the separation of concerns that is the raison d’etre of MVVM and which produces benefits such as better maintainability and testability.
It is possible to use events for communication between View and ViewModel because the View has a direct reference to the ViewModel and can therefore subscribe to events on the ViewModel. But what about when you want one ViewModel to communicate with another ViewModel? While you might be tempted to create a direct reference between ViewModels, the result would be a tight coupling that can make the app structure more brittle and harder to maintain. While this may seem innocent enough at first, over time you can end up with spaghetti code. To take the pasta analogy a step further, what MVVM tries to do is provide better maintainability by separating the app into layers, like lasagna. If you have ViewModels referencing one another, you’re introducing spaghetti back into the recipe and will end up with bad case of indigestion.
A classic way to address this problem is by funneling inter-ViewModel communication through a mediator, also called an event aggregator or message bus. This is why I incorporated a MessageBus class into my Simple MVVM Toolkit. It has a Register method, which accepts a string token and a method to callback when someone sends a message to the bus using the specified token. There is also an Unregister method you can call when you no longer wish to receive messages (make sure to call this when doing clean-up in your ViewModel’s Dispose method). More than one ViewModel can register to receive messages, which are broadcast to subscribers in a fire-and-forget manner. The Notify method will transparently marshal the call to the UI thread, while BeginNotify will invoke the subscriber’s method on a Thread Pool thread (for non-UI operations).
The payload of a message is the NotificationEventArgs class, which is also used for event-based communication between Views and ViewModels. The nice thing about this class is that it overloaded constructors that accept a TOutgoing type argument, so you can pass any object in a strongly-typed manner, as well as a TIncoming argument for passing data from the message recipient back to the sender, for loosely-coupled two-way communication via the MessageBus.
A great example where the MessageBus comes in handy is application navigation that is driven by logic in a ViewModel. Typically the MainPage View will contain a navigation Frame element with its Source property bound to a property on its ViewModel that is of type Uri. When the ViewModel sets this property, displays the desired page in the frame, usually with the assistance of a UriMapper.
<navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}" Source="{Binding Path=SelectedPage, Mode=TwoWay}" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed"> <navigation:Frame.UriMapper> <uriMapper:UriMapper> <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/> <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/> </uriMapper:UriMapper> </navigation:Frame.UriMapper> </navigation:Frame>
Notice the three hyperlink buttons sitting on the main page. Each has a Command property that is bound to a NavigateCommand property on the ViewModel. For the CommandParameter each passes the name of a View. All the Navigate command does is set the SelectedPage property to a Uri constructed using the name of the passed-in page name.
<HyperlinkButton x:Name="customerLink" Style="{StaticResource LinkStyle}" Command="{Binding Path=NavigateCommand}" CommandParameter="CustomerView" TargetName="ContentFrame" Content="customer"/>
private void Navigate(string pageName) { Uri pageUri = new Uri("/" + pageName, UriKind.Relative); this.SelectedPage = pageUri; }
So far, none of this requires communication between two different ViewModels. But what if you wanted to navigate to a particular page based on logic in a ViewModel shown in the navigation frame. For example, on the CustomerView you have a Save button, which when clicked will cause the Home page to be displayed in the navigation frame on the main page. To accomplish this feat you would want to send a message from the CustomerViewModel to the MainPageViewModel with the name of the page to display. Enter the MessageBus!
public void Save() { MessageBus.Default.Notify(MessageTokens.Navigation, this, new NotificationEventArgs(PageNames.Home)); }
The Notify method passes a message token string, which is defined as a constant in the MessageTokens class. Message senders and subscribers simply agree on the token used to exchange messages. Also passed in the name of the page we want to navigate to, which in this case is the Home page.
In the constructor of the MainPageViewModel we subscribe to receive messages for the Navigation message token by calling the Register method on the MessageBus and passing both the token and a callback method, which is an EventHandler<NotificationEventArgs>.
public MainPageViewModel() { MessageBus.Default.Register(MessageTokens.Navigation, OnNavigationRequested); } void OnNavigationRequested(object sender, NotificationEventArgs e) { Navigate(e.Message); }
Notice that the callback method simply calls Navigate passing e.Message, which was set by the CustomerViewModel to be the name of the Home page (which happens to be “Home”). Pretty cool, eh?
So there you have it. You can download the sample Mvvm Navigation app as part of my Simple Mvvm Toolkit. Also included is a Messaging sample app that demonstrates multicast and two-way messaging. Enjoy.





Tony, can you use your simple mvvm with authentication, authorization using message bus? I admit I do not know anything about prism mef navigation, silverlight is this possible? Thanks….
usi
Pingback: Building a Leak-Proof Eventing Model | Tony Sneed's Blog
Yes, the way to integrate authentication and authorization into a Silverlight app with Simple MVVM Toolkit is to use the project template called “SimpleMvvmRiaServices,” which uses WCF RIA Services. Here is a nice article on how to do that:
http://www.silverlightshow.net/items/WCF-RIA-Services-Part-7-Authentication-and-Authorization.aspx
Cheers,
Tony
Hi Tony,
I’ve been using your toolkit, I wanted to use this approach to support navigation in our application however the MessageBus is marked Internal. Am I doing something wrong?
The most convenient way to use the MessageBus is to call two methods in the base ViewModel class: SendMessage, RegisterToReceiveMessages. Take a look at the sample app for navigation that comes with the toolkit for an example of using these methods for ViewModel-driven navigation.
I am planning to make the MessageBus itself public in the next release of the toolkit, so that you will be able to exchange messages from classes that do not derive from ViewModelBase.
Cheers,
Tony
Unfortunately that’s my current situation. We use a Navigation manager outside of the view models. That’s why the source shown in this post was so compeling. I’ll either modify the source or look at a different solution for message. Thanks for your time.
No need for that. I’ve already posted the code for Simple MVVM Toolkit that exposes the MessageBus as a public class.
http://simplemvvmtoolkit.codeplex.com/SourceControl/changeset/changes/11617
In the next week I’ll incorporate this into the 2.1 release of the toolkit.
Thanks Tony,
With a little bit of effort that worked.
I wasn’t able to use
MessageBus.Default.Register(MessageToken.Navigation, OnNavigationRequested);
void OnNavigationRequested(object sender, NotificationEventArgs e)
{
}
like you showed above however I got the following to work.
MessageBus.Default.Register(MessageToken.Navigation, [instance of Navigation]);
public class Navigation : INotifyable
{
public void Notify(string token, object sender, NotificationEventArgs e)
{
}
}
Thanks for all your help.
Regards
Artin
FYI, installing simple MVVM from within vs2010 fails with error on finding it.
it shows it in MS extend dialog, and if you click on download, it then launches browser
and you get error.
In MS website, again you get error,
go to codeplex and grab the exe and all is good,
just thought you should know.
I hope this works well, and most important works on Mono for simple MVVM goodness
in moonlight on linux .
t
It should work now. I re-uploaded the toolkit to the Visual Studio Extensions Gallery and tested it. Also, you might want to re-download the toolkit — I discovered and fixed a small bug and included a sample for validation with RIA Services.
Pingback: Commands versus Event Triggers in MVVM | Tony Sneed's Blog
Can a view use the messagebus register method to receive a message from a viewmodel? I tried to mimic MessageBus.Default.Register(MessageToken.X, OnX);
void OnX(object sender, NotificationEventArgs e)
{
}
but OnX is not INotifyable?
For communication between a View and its ViewModel, you should use event notifications instead of the MessageBus. Check out this blog post on the topic: http://blog.tonysneed.com/2011/01/28/tackling-the-problem-of-modal-dialogs-in-mvvm.
On the other hand, it is possible to send messages between other kinds of classes, for example, between two views, or to and from the Application. For that you have a couple choices. You could implement INotifyable if you want to register to receive messages but don’t want or cannot unregister. This will allow subscribers to be garbage collected and not result in a memory leak. If, however, you don’t mind manually unregistering subscribers, there’s no need to implement INotifyable. Simply, register to receive messages, then unregister when you are no longer receiving messages, probably by implementing IDisposable.
Cheers!