One of the recurring aspects about MVVM programming is the use of messages. A message can be considered as a kind of an application wide event and therefore accessible from any part of it.
The idea with this pattern is to have a component which is referenced by any part of the application that wants to listen or to send messages. This component (which has given its name to the pattern) is commonly know as the mediator and allows us to create an architecture in which senders and listeners do not know each others in order to obtain a better modularity.
The nRoute framework includes a messenging framework that can send messages both synchronously and asynchronously. This part of nRoute is based on the Rx framework for its implementation. Those who have already used Rx will feel confortable.
One common problem when following the MVVM pattern is to open a ChildWindow from a view model and to get its results when it’s closed in the view model.
We will now see how to do this by using messages.
We build an application that displays a list of contacts which we will be able to edit when clicking on a button. This button will open a ChildWindow displaying the fields to edit the contact. It will also be possible to validate or to cancel the changes.
Here are the screenshots of what is expected :
Our main control is Home.xaml. This is the one showed on figure 1. The Xaml code of this control contains a ListBox templated to display the contacts and a Button bound to a command that opens the contact’s edition ChildWindow. Here’s the Xaml of this control :
And its code-behind :
You can see here that thanks to the MapView attribute, the Home control is linked to the HomeViewModel. But before defining this view-model let’s fist define the model representing the contacts:
The particularity of this view-model is that it implements the IEditableObject interface which you can find in the System.ComponentModel namespace. This interface defines three methods we’ll use to create the contact’s edition form of the ChildWindow :
BeginEdit (sets the object in a edit state)
CancelEdit (cancels all modifications and stops the edition)
EndEdit (validates all modifications and stops the edition)
And now here’s the HomeViewModel :
In its current state, the view model generates a list of 10 elements and defines the EditContactCommand command that is called whenever the Edit button is clicked. Therefore, it is in the BeginContactEdition method that we want to open the ChildWindow passing it the current contact.
We will now add a ChildWindow to the project using Visual Studio’s template and modify it to make the Xaml be like this :
Creation of messages
The mediator pattern induces three things :
We need a message to send
We need something to send the message
We need at least one control that listens to the message
The control sending the message must provide enough information inside the message in order to make it useful for the controls that listens to it.
In our application we will have two messages, one to trigger the contact’s edition and another one to inform that the contact’s edition is finished.
Sending and receiving messages
Now that we have messages we need to send them. And as everyone should be expecting, we will start by the one that triggers the contact’s edition.
Let’s go back to the HomeViewModel class and add the following field :
We will initialize it inside the constructor with the default communication channel associated with the BeginContactEditionMessage message (private channels also exists but it is out of the scope of this article) :
We now need to modify BeginContactEdition with the following code :
The OnNext method sends a message to all listeners (those who have already used Rx will feel confortable here). The message is now being sent but nothing listens to it.
The one that should listen to it is of course the ChildWindow. Let’s modify its code-behind a little to make it react to the messages sent by the view-model.
We will add two line to it’s constructor :
As in the view model, we get the public instance of the communication channel but this time we will not call OnNext (which stands for Send) but Subscribe (which stands for Listen). The Subscribe method takes an Action as a parameter which will be called whenever a message is sent and returns an IDisposable object we must dispose to unsubscribe from the channel.
For the moment, we will save this value in a field :
Then we will implement the BeginContactEdition method :
In order to make things correctly we’ll make the ChildWindow implement IDisposable :
And that’s it ! Now, when we select a contact in the ListBox and then click on the button the ChildWindow opens with the selected contact in edition mode. But the view model is never notified when the contact’s edition is finished.
We will do the same thing for the EndContactEdition message that what we did the BeginContactEdition but reversing the roles of sender and listener.
In the ChildWindow’s code-behind we will replace the event handlers of the buttons OK and Cancel by the following code :
Let’s go back to the view model and follow the same method for the EndContactEditionMessage message that the one use in the ChildWindow’s code-behind to receive the BeginContactEditionMessage.
Creation of the IDisposable field :
Modification of the view model’s constructor :
Make the view model implement the IDisposable interface :
I hope that you’ll find this article useful.
As usual, you can download the sources of the articles on my skydrive.