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

54 thoughts on “More than Just MVC for WPF

  1. Wow!! Great work, Marlon. 🙂

    Throughout the whole article, I kept thinking “You can do this with ICollectionView” but then you mentioned exactly that. So, my question to you is, what difficulties has this Mediator technique resolved for you? Your demonstration of it was to keep the current item in sync across two views, but that isn’t the problem you needed to solve. I’d love to know the “real” problems where this pattern is useful.

    Also, putting the data model and input processing code into one “controller-like” class is very similar to the ViewModel of MVVM. What do you see as being the key difference between your MVC + M and MVVM?

    Keep up the awesome work!

    Thanks,
    Josh

  2. So let me start by the difference between MVC + M and MVVM. In MVVM there are 3 Entities. The Model , View and ViewModel. In the MVC + M there is the Model, View, Controller and the Mediator. The MVC+M can also be translated to MVVM + M. You may even want to use it as MVP + M. I called it + M and not MVCM because the final M (the mediator) ADDS on to the pattern that you are using. The Mediator makes communication between Controllers/ViewModel/Presenters possible.

    Now a real life example would be the same as the one I mentioned (The Product App) but with a Hierarchal data source. If you have a Hierarchy you cannot use the ICollectionView to get the currently selected item (this is just one example).

    I am using this in a project where there are multiple controllers and they send messages. Then there is a “Master Controller” that reads the messages and once it gathers all the messages it needs, it requests data from the Model. Basically there is a TreeViewController and a TimeController involved. The TreeViewContoller does not know that the TimeController exists and vice versa. The “Master Controller ” knows of both of them so it waits for them to send their message and when the messages from both of them come in, it requests the data from the Model.

    I would strongly suggest to download the source code and have a look at how this all fits together.

    Please let me know if this makes things more clear…

  3. Thanks Marlon, that clears it up a bit for me. I’m not sure what you mean by “f you have a Hierarchy you cannot use the ICollectionView to get the currently selected item” though. Every collection has its own ICollectionView, and as long as the controls which bind to it are Selectors with IsSynchronizedWithCurrentItem set to true, it should work out OK. But, anyways, your clarification definitely makes sense to me.

    Thanks,
    Josh

  4. IsSynchronizedWithCurrentItem would only work for the root list but not for the children. For the children you would have to create another ICollectionView…. Well this is as far as I know…. Maybe I am wrong after all 😀

    Yet even if the ICollectionView would support Hierarchies there are cases that you must move away from WPF details and be more structural in your code. In that way you code will be more abstract and you can use it not only in WPF but even with other technologies

    Regards

  5. This is a really clean way to get Controllers to talk to each other with no coupling. With respect to the above, as I see it there is no reason why the one should depend on a specific feature in a framework. Abstractions of this type also mean that you could conceivably use this sort of pattern in, say, a Win32 or even a GUI-Less environment if you wanted to.

    Heck, you could probably even use it in (Marlon might want to sit down and cover his ears now) Java if you were so inclined 🙂

  6. Marlon,

    Suggestion: The seach is case sensitive; may want to change this.

    What does this buy you in a very large application. Using the system could require 1,000’s of messages to be declared, right?

    Thanks for sharing this. I love to read and look at other possible ways to solve a problem.

    Cheers,

    Karl

  7. Hi Karl,

    Thanks for the search suggestion…

    “What does this buy you in a very large application? Using the system could require 1,000’s of messages to be declared, right?”
    I would not say that you would declare loads of messages because messages are related to features. So you would have 1,000’s of messages only if you have 1,000’s of features.

    The buy here is that Controllers can communicate with each other via the Mediator without knowing about each other. In the example the ProductListController communicates with the ProductDetailsController via the mediator. This communication did not introduce any coupling. And that is where the Mediator comes handy because you can have Controllers talking with each other without knowing about each other.

    Besides this you can then use this system for more complex things…
    For example, in one of the application I was working on recently, I needed to have a controller that selects time. When the time is selected, this Controller would send a message so the other Colleagues registered to the Time Selection message would do some operation with the Time that is passed to them.

    I needed to introduce a new feature called pre-fetching, where the time selected gets expanded a bit so that you request more data than you actually need, so that the user experience is better when the user is selecting time. All I needed to do was to create the Prefetch Controller and redirect the TimeController messages to this new PrefetchController. The Prefetch Controller would then change the time selected by expanding it. All other controllers did not know that such a thing is happening. Not even the TimeController itself 🙂

    This shows how this system can help you make changes to your application without changing all entities. It’s like every entity does 1 job and has no coupling with others.
    I think that I did a bad example here in the post so I am thinking of writing a Part 2 for this to make myself even clearer…

    If you have any idea or suggestion please let me know so that I add them to the new post 🙂

    Thanks Karl
    Regards Marlon

  8. Josh,
    I was about to mention how it sounds a lot like the CAB Event Broker. I think it’s a great idea. Perhaps, you could register commands you’re interested in with the broker similar to how you register a routed command with the command manager now.

    What if we forgot about registering commands altogether and created commands that contained their implementation. That way when I say that my menu item executes the MyAppCommands.ConnectToDevice command, MyAppCommands.ConnectToDevice knows how to execute itself.

  9. Mike,

    Sure, non-routed commands have their role to play. I prefer them to be a “disconnected” from the rest of the app, to keep them clean and modular. If a regular ICommand needs to talk to the data model, then I’d prefer to keep the implementation in a Controller instead. But for something like “OpenWebPage” then it makes perfect sense to wrap that up in a normal command. That’s my opinion, anyways.

    Josh

  10. The Cabpedia event broker is very similar in purpose and concept to Marlon’s implementation. The event broker
    uses strongly typed delegates, while [INSERT MODEL/VIEW PATTERN HERE]+M uses direct method calls against a
    known interface. They also differ in how the wiring is declared, but that’s about it – implementation details. They’re different approaches to the same problem.

    Mike Brown: I can see the attractions of using self contained command objects, but wouldn’t that limit the flexibility
    somewhat? To expand on your example, what if you wanted to keep the option of adding, for example, another UI Element
    that can also react to the MyAppCommands.ConnectToDevice command?

  11. Pingback: Dew Drop - March 21, 2008 | Alvin Ashcraft's Morning Dew

  12. Pingback: Creating a File Explorer in WPF using MVC+M « C# Disciples

  13. Pingback: “The Next Web aka Web 3.0” and Silverlight's importance to it. - Corey Gaudin

  14. Hi Marlon,

    Thanks so much for sharing.
    In my project, i am facing the same problem.
    I have 5 controllers and i don’t know how to communicate each other in loosely couple manner. Now i have a great idea how to handle it.

  15. Do you happen have any examples of the unit tests that would come with this example? I am not sure how I would test the “fire” of a Command from the view which is registered with a .net object.

    Also, what mock object are you guys using, I am familiar with NMock but now they switched to NMock2 I am not sure if it wouldn’t better to use one of the other ones out there, like RhinoMocks or Moq, or anything else I am unaware of.

    Thanks

  16. Hi,

    Thanks for the examples, they seem like a great way to handle MVC with WPF (two things I’m trying to grasp and learn simultaneously). A couple problems I’m running into now though that I’m wondering if you (or anybody reading) has a solution to are:

    1) I’ve got a login page with a button to submit it. I’m using a command like your example but how should I be handling passing multiple values through a command? I see I can use a multibinding which would ultimately mean having to write a converter it appears and rather drastically over complicates the whole procedure.

    2) How would you deal with regular events when you want to perform an action (such as say running some code when the user types in a textbox). Would you go the codebehind event handler and then just call a method in the controller?

    Thanks!

  17. Pingback: WPF Line-Of-Business labs and Silverlight vs. Flash | Tamir Khason - Just code

  18. Pingback: Silverlight Travel » WPF Line-Of-Business labs and Silverlight vs. Flash

  19. Pingback: sachabarber.net » MVVM Mediator Pattern

  20. Pingback: Mediator v2 for MVVM WPF and Silverlight applications « C# Disciples

  21. Hi marlon,
    This was a very good article for WPF beginners like me, i was wondering how to pass multiple command parameters through button using your pattern. Appreciate if you could help me in this

  22. Marlon,

    Love the example.

    If you really want people who are new to patterns, MVC, WPF or any/all to fully grasp the concept and power I would suggest placing each controller in it’s own assembly. Demonstrate that Marlon.ControllerA.dll does not reference Marlon.ControllerB.dll or vice-versa. If you have the time and inclination you could also change object args to string args, serializing and deserialing XML across machine boundaries. Of course, it takes me a lot less time to make that suggestion than for it to bear fruit lol. This is, of course, the true inherent power in a truly decoupled tier and/or controller. In your case the +M could reside anywhere (as you already know), with the caveat you couldn’t pass args as an object (reference) obviously.

    Thanks again, adding your blog to my subscriptions. Wish I had time to add as useful posts to my blog lol…

  23. Marlon,
    Thanks for preparing this blog post! I’m a WPF beginner and really liking learning more about this technology. More power to you!

  24. Nice article but I don’t understand why you are changing the names of well defined patterns.
    What you call controller is usually called ViewModel or PresentationModel (Fowler).
    Controllers are used to orchestrate view creation “see Prism”.
    What you call mediator is usually called Publish/Subscribe Notification Service (Fowler).

  25. Hi Marlon, I liked this article a lot (I know that it’s a little old). I see it more appropiate for a development environment where programmers are learning not just a pattern but the very WPF itself. I think that using the moderator solves the issue of beeing so disconnected (which in my case I could not find any help from MVVM documentation).

    The question is if you are still using this pattern or maybe something else (¿MVVM?) ?

    best regards
    Rodrigo

  26. Pingback: MVC -- Kommunikation unter Controllern?! - Delphi-PRAXiS

  27. Thanks for one’s marvelous posting! I certainly enjoyed reading it, you are a great author. I will be sure to bookmark your blog and will come back very soon. I want to encourage you to definitely continue your great posts, have a nice holiday weekend!

  28. Marlon, excellent write-up and example. I have been walking through the code this afternoon and I learned more doing that than reading all of the other MVVM articles combined.

    As you mentioned, it’s an old article, and, I’m a WPF noob. Do you know whether some new features have been added to later versions of the .NET framework that support some of your ideas, for example, something like your Mediator/IColleagure facility.

  29. First of all thanks for this great post. I have read your post and downloaded the sample. I then applied this Mediator pattern with MVVM. And I got it to work fine. I just saw a small problem in that.

    Sometimes in some cases it happens that NotifyColleagues Method is called just before the Register method of the Mediator class. So, the ViewModel that called Register Method is not notified.

    I have created a sample project. Please take a look at it. You can download the sample here:
    https://drive.google.com/file/d/0B5WyqSALui0bZFlBaGpzZXU5OXc/edit?usp=sharing

    If you download the sample then please follow the steps below:
    1. Run the Program.
    2. At this time you cannot see anything on left sidebar. (Might be due to above mentioned problem). Click on any other Item.
    3. Now sidebar has some items.
    4. Click on any other Item in sidebar.
    No changes on the right hand side of the screen (might be due to above mentioned problem)
    5. Select another item from sidebar. This time you can see some text.

    Can you suggest some fixes to this problem?

Leave a reply to Arun Cancel reply