More than Just MVC for WPF

Introduction

First of all I am assuming that the readers already know how to use the MVC design pattern for WPF (or at least read about it and understand the concept). If not I would suggest that you read this brilliant post by Josh Smith. I am writing this article because recently I found a problem when using the MVC in WPF and I think I found a neat solution. Well I said that “I” found the solution, that is not true. The pattern that I am going to talk about is called the Mediator Pattern and I found it in the Gang of Four book that I was reading recently. I decided to mix the 2 patterns together and the result was beautiful code.

Warning: This article is a bit long. Readers can fall fast asleep 😀

Problem Definition

The way I see it, Views must be as small as possible and handle only one specific job. Let’s do a practical example. Let’s say we have an application that displays a list of products. The application also lets you click on a specific product and the details of that product would show on the side. A search feature is also provided in this application. So our application would look something like this (I coloured the different sections of the app to make them more obvious)

Let me introduce the Entities that we have here

Controllers (These are simple class nothing more)

– ProductListController

– ProductDetailsController

– SearchController

Views (These are all User Controls)

– ProductListView

– ProductDetailsView

– SearchView

All views create an instance of the related Controller and set the Controller instance as the DataContext. By doing this the View can data bind to the properties of the Controller and also the Controller can handle routed command and routed events from the View since the Controller is now in the WPF logical tree. In this way the View has 0 lines(excluding the InitializeComponents) of code in the code behind file and all logic is inside the Controller class. By doing this you can easily Unit Test the logic and also Designers can use tools such as Expression Blend without having any problem because the logic is handled in the controller class and not in the view itself. Just like MVC in Web so to speak. Imagine commands in WPF as being the Routed URL for the controller to handle.

One may say “Wow, that’s a lot of classes” but hey if you want to be flexible, scalable and have code reusability that is the way to go. If not, then go ahead and put everything in one class but the result will be strongly coupled entities that are not reusable. Sometimes this is perfectly acceptable and so YES go ahead and do that. But let’s say you need to do a Search feature in another page. With MVC you can just re-use the search view and search controller in the other page.

In the MVC for WPF (or better in one of the implementations), there is a strong use of Routed Commands (sometimes one may use also Routed Events, well at the end of the day a RoutedCommand is just a Routed Event + the Command Pattern nothing more). The problem with Routing Commands is that the communication is always done from child to parent in the logical tree. In the application above there is a need of something different. Basically the Controllers need a way how to communicate. Yet we do not want that the Controllers know about each other because if that was so why not create 1 View and 1 Controller. We must ensure that no coupling is made between the controllers.

In the sample application above the ProductListController is handling the SelectionChanged event of the ProductListView. ProductListController needs to communicate this to the ProductDetailsController so that it updates the data that is currently being shown in the ProductDetailsView.

The question is how can you achieve this?

The Mediator Pattern to the rescue

The Mediator pattern can be described as a ChatRoom. In a Chat room there are Colleagues (the persons in the Chat Room) and via the Mediator (the chat room itself) they exchange messages. The same can be applied for our Controllers. There would be 1 Mediator and all Controllers communicate to each other via the Mediator. In simple english the Colleagues would be the Controllers.

The following is the Class Diagram for the application I mentioned above

The interface for the Mediator would look something like this

The signature of the methods would look like this

/// <summary>
/// Registers a Colleague to a specific message
/// </summary>
/// <param name="colleague">The colleague to register</param>
/// <param name="messages">The message to register to</param>
void Register(IColleague colleague, IEnumerable<string> messages);

/// <summary>
/// Notify all colleagues that are registered to the specific message
/// </summary>
/// <param name="message">The message for the notify by</param>
/// <param name="args">The arguments for the message</param>
void NotifyColleagues(string message, object args);

The IColleague interface is an interface that all Controllers implement and looks like this

The Signature for the MessageNotification would look like this

/// <summary>
/// Notification from the Mediator
/// </summary>
/// <param name="message">The message type</param>
/// <param name="args">Arguments for the message</param>
void MessageNotification(string message, object args);

Aha…. but Marlon how does this solve the Problem ??!!??

With the Mediator pattern Controllers can send messages to each other without knowing of each other. Let’s do an example to try and make this more clear. Lets use the problem that I described above.

ProductListController is handling the SelectionChanged event of the ProductListView. ProductListController needs to communicate this to the ProductDetailsController so that it updates the Data that is currently being shown in the ProductDetailsView”

All we need to do is 3 things

1.0 ProductDetailsController registers to the SelectProduct message (the message is just a constant string defined in a common class named Messages)

1.1 ProductDetailsController updated the Selected Product when this message is sent.

2.0 ProductListController sends a message via the Mediator that a new product has been selected

Code for 1.0

public ProductDetailsController()
{
    //register to the mediator for the SelectProduct message
    Mediator.Register(this, new string[]
    {
        Messages.SelectProduct
    });
}

Code for 1.1

/// <summary>
/// Notification from the Mediator
/// </summary>
/// <param name="message">The message type</param>
/// <param name="args">Arguments for the message</param>
public override void MessageNotification(string message, object args)
{
    switch (message)
    {
        //change the CurrentProduct to be the newly selected product
        case Messages.SelectProduct:
            CurrentProduct = (Product)args;
            break;
    }
}

This will set the CurrentProduct property of the ProductDetailsController to be the new product that has been selected (the product object has been sent via the Code in 2.0). The CurrentProduct property of the ProductDetailsController is being data bound in the view. When the CurrentProduct is set the property raises a PropertyChanged notification, so that the binding is updated with the new value.

Code for 2.0

//event handler for the selection changed
void SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    //Notify that the selected item has changed
    if(e.AddedItems != null && e.AddedItems.Count > 0)
        Mediator.NotifyColleagues(Messages.SelectProduct, e.AddedItems[0]);
}

And this is what I call the MVC + M

hehe… Funny name but for me this is doing miracles. I am currently using this in one of my projects at work and I can confirm that this absolutely works. One may say but this application could have been done with other thing that WPF offers, and I agree 100%. The example application that I used in this post can be easily implemented by putting the list of data in the Model and binding to it (like in MVVM). For the selection part, you can use the Current item of the ICollectionView and everything would work. Yet when you need to do more than just “Select item and data changes somewhere else” than the MVC + M comes useful.

Conclusion

MVC + M is a neat mix of the MVC pattern with the Mediator pattern. The MVC makes things much easier to test and much more isolated and controlled. The Mediator makes communication between Controllers possible in a loosely coupled manner. For me this works really well and I hope that it will do the same for your applications. Download the source code to have a look at my humble implementation.

Any comments, questions and suggestions are as usual most welcome…

P.S I am sorry if this post was a bit long but I didn’t manage to make it any shorter.

See also Part 2

Download the Source code of the Sample Application

kick it on DotNetKicks.com