Using Model View Presenter in WPF

I have owned a copy of Sams Teach Yourself WPF in 24 Hours for about a year, and I still find it an interesting book. One thing I like about this book is that doesn't just show off WPF features - it shows how to use the Model-View-Presenter pattern in doing so. The book was written by Rob Eisenberg and Christopher Bennage from BlueSpire, who are also the guys behind the Caliburn WPF framework, so they know a thing or two about the Model-View-Presenter pattern.

Like the Model-View-ViewModel pattern, we can mostly agree upon what the MVP pattern is, but in practice nearly every implementation looks different. I want to highlight some of the differences between my approach to MVP and theirs, and I have attached a sample application that demonstrates these.

Sample

As in the Teach Yourself WPF in 24 Hours book, my sample application is a contact manager. Here are the key points:

  • The application has a shell, and a docking panel like Visual Studio.
  • There are two types of views that can be opened - a Contact List, a Contact Details for an individual contact
  • It uses Composite WPF for region management and loosely coupled communication
  • It uses Autofac 2.0 Beta for IOC
  • It uses AvalonDock for tab management

You can download the code to follow along. You can also download the Teach Yourself WPF Contact Manager from the Sams website (you may need to register before the download appears).

Contact Manager Composite WPF with MVP Sample

Model-View-Presenter Differences

First let's highlight some differences in terms of approaches to the MVP pattern between the two. Martin Fowler splits the MVP pattern into Passive View and Supervising Controller, but if anything I think both approaches are Supervising Controller, just in a different way.

View->Presenter Communication

The first example is in how views and presenters communicate. In Teach Yourself WPF, views can hold a reference to the presenter - the following code is for a button click event handler:

private void Save_Click(object sender, RoutedEventArgs e)
{
    Presenter.Save();
}

An illustration of View-Presenter communication in Teach Yourself WPF

In my approach to MVP, Views should be independent of the presenter and not hold a reference to it, though they may be bound to a Model. If a view really wanted to communicate with a presenter, it would do so via raising an event:

event EventHandler SaveRequested;

private void Save_Click(object sender, RoutedEventArgs e)
{
    var handler = SaveRequested;
    if (handler != null) handler(this, EventArgs.Empty);
}

An illustration of View-Presenter communication the traditional way

(Of course, this is assuming that in both examples, we aren't using WPF Commands)

Some considerations to keep in mind here are:

  • In the Teach Yourself WPF way, the Presenter needs a reference to the View, but the View also needs a reference to the Presenter. For loose coupling to work, both of these should be interfaces, which may require a second interface. Using events, you normally create an interface for the view - there is no need for an interface for the presenter, since the view does not need to reference it.
  • On the other hand, testing is made a little easier with Teach Yourself WPF approach. To simulate the click event, you just have to call the method on the presenter. But to simulate the click event in the eventing approach, you have to mock the view and raise the mock event.

Presenter is DataContext?

One pattern the Teach Yourself WPF book uses, and Caliburn too, is that the Presenter is normally the DataContext for the view. This is different to the approach I've normally used, where data context is a separate object - either a domain model object, or a view model object that the presenter manipulates.

One benefit of this is that in the Teach Yourself WPF approach, properties on the presenter are available for direct binding. A presenter can use some code like this:

public void Initialize() 
{
    Contact = LoadContactFromDatabase();
}

public Contact Contact { get; set; }

However, in my approach, the presenter normally sets properties on a Model object, which it assigns to the view:

public void Initialize() 
{
    View.Model = new ContactDetailsModel();
    View.Model.Contact = LoadContactFromDatabase();
}

The Model property on the view is just a wrapper around the data context, but the key point is the DataContext is not the presenter - it is a different object. The presenter can manipulate the model, and the view can manipulate the model, but the view doesn't touch the presenter (except perhaps indirectly via raising events).

A similar thing happens with Commands. In Teach Yourself WPF/Caliburn, a command would be exposed to the view by a property on the presenter. In my approach, the presenter gives the command to the model, and the view gets it from the model.

public void Initialize() 
{
    View.Model = new ContactDetailsModel();
    View.Model.Contact = LoadContactFromDatabase();
    View.Model.SaveCommand = new DelegateCommand(SaveExecuted);
}

Here are some points to consider:

  • The Teach Yourself WPF approach is simpler because it requires less code - you don't have to create a separate class for the model.
  • However, it does put both state and behavior in the same object. In the approach I have used, state and behavior are separated.

Is it MVVM?

Though Teach Yourself WPF/Caliburn use the term presenters, some of the points above make me feel almost as if they are closer to the MVVM pattern than the MVP pattern. In MVVM:

  • The ViewModel is usually the DataContext (check)
  • The View binds to properties on the ViewModel (check)
  • The View holds a direct reference to the ViewModel (check)
  • The ViewModel typically contains both the state of the view and it's behavior (check)

The one thing Caliburn and Teach Yourself WPF do that wouldn't fit the MVVM profile is that the Presenter holds a reference to the View - something ViewModels should never do. However, in many ways it feels that the Presenters in Teach Yourself WPF/Caliburn are closer to the MVVM pattern than they are to the traditional MVP pattern.

Model-View-Presenter-Parameter

Another object that I have created for each view is a Parameter object. When you open a view, it's common to need to pass arguments to the presenter - such as a customer ID, filter information, and so on. Instead of making these properties on the presenter, the pattern I follow is to put them in a separate object. This is a technique I learned at from a client, and though it seemed redundant at first, it has grown on me.

For example, in the sample application, when you click a contact, the ContactDetailsPresenter is shown for that contact. The parameter object looks like this:

public class ContactDetailsParameter : Parameter
{
    public ContactDetailsParameter() : this(0)
    {
    }

    public ContactDetailsParameter(int contactId)
    {
        ContactId = contactId;
    }

    public int ContactId { get; set; }
    public bool IsNew { get { return ContactId == 0; } }
}

The presenter can make use of these arguments when initializing the view:

public class ContactDetailsPresenter : Presenter<IContactDetailsView, ContactDetailsModel, ContactDetailsParameter>
{
    protected override void Initialize()
    {
        View.Model = new ContactDetailsModel();
        View.Model.SaveCommand = new DelegateCommand(SaveExecuted);
        View.Model.Contact = Parameter.IsNew 
            ? new Contact() 
            : _contactRepository.GetContact(Parameter.ContactId);
    }
}

The key benefit that parameters have is that you can use them to identify information about a view, without actually creating the presenter or view. This is common when you want to re-activate an existing view.

In the sample application, you can click a contact and they will open in a new tab. If you click another contact, another tab opens. But if you click the same contact a second time, you don't want a new tab to appear - instead, you might want the currently open tab to get focus.

To open a view, I normally raise a Composite WPF event:

private void ShowContactExecuted(Contact contact)
{
    EventAggregator.GetEvent<ShowViewEvent>().Publish(new ShowViewRequest(typeof(ContactDetailsPresenter), "ContentPane", new ContactDetailsParameter(contact.Id)));
}

The arguments are:

  1. The type of presenter
  2. The region name to insert the view into
  3. The parameter, with all the arguments the presenter needs

There is a singleton event listener which receives that event and works something like this (simplified):

if (region.HasMatchingView(parameter))
{
    region.ActivateView(parameter);
}
else 
{
    var presenter = Container.Resolve(presenterType);
    region.Add(presenter.View, parameter);
}

The logic for deciding whether to re-use the view in the parameter is implemented like this:

public ContactDetailsParameter(int contactId)
{
    ContactId = contactId;

    // Use the same view when ContactID's match, but for new views, never reuse them.
    ReuseViewBy(() => IsNew ? (object)Guid.NewGuid() : ContactId);
}

While this approach has many upsides, it does increase the number of files needed for a full MVP view:

Solution Explorer showing views

The upside however is that you do get a flexible, consistent approach to views that can handle pretty much any scenario - and having used this pattern in a fairly complicated LOB application, I'm pretty confident that it can handle anything. A good New Item template for Visual Studio can greatly speed up the getting started time too.

Some things to consider:

  • A parameter is a good way to encapsulate the arguments for a presenter
  • But it does introduce an extra class, though that in itself has some benefits

Composite WPF Regions vs. Presenter Hierarchies

I have used Composite WPF in five client projects now and I'll continue to do so. It's a fantastic piece of work that does help you to solve many common scenarios without being overly controlling. The major feature Composite WPF brings for me is regions, which allow you to compose and nest views, and allow the to communicate via the event aggregator.

Composition is an aspect of Teach Yourself WPF/Caliburn that I really don't feel comfortable with, especially from a Composite WPF background. Check out the Caliburn documentation on presenters. Depending on your UI, you can choose from:

  • Presenter
  • Navigator
  • PresenterManager
  • MultiPresenter
  • MultiPresenterManager?

Each of these are kinds of presenters and serve to fulfill a specific composition pattern. They are necessary because, for example, if you have a view with two child views, the parent view's presenter needs a reference to the child presenters, and vice-versa sometimes, so they can communicate. It reminds me of the CAB SmartPart/Workspace approach.

The Composite WPF region approach does away with all of this. Here's the start up code for the sample application:

_container.Resolve<IEventAggregator>().GetEvent<ShowViewEvent>().Publish(new ShowViewRequest(typeof(ShellPresenter), "Shell", new ShellParameter()));
_container.Resolve<IEventAggregator>().GetEvent<ShowViewEvent>().Publish(new ShowViewRequest(typeof(MenuPresenter), "Menu", new MenuParameter()));
_container.Resolve<IEventAggregator>().GetEvent<ShowViewEvent>().Publish(new ShowViewRequest(typeof(ContactListPresenter), "ContentPane", new ContactListParameter()));

This code opens the Shell, and injects the Menu and ContactList into it. However, the Shell view has no notion of either of them - the ShellPresenter is just a presenter, not some kind of MultiPresenterManager. If it needed to communicate with them, it could do so via a loosely coupled pub-sub model called the Event Aggregator.

Keep in mind that the Composite WPF region system would work just as easily with a Teach Yourself WPF presenter approach (presenter as DataContext, etc.). The composition approaches aren't necessarily exclusive either - hierarchical presenters as used with Caliburn can work alongside regions.

Conclusion

In this post I focused on two alternative approaches to implementing the Model View Presenter pattern - a traditional, strict approach with strong separation between state and behavior, and the Teach Yourself WPF/Caliburn approach which is a nice intermediary between MVP and MVVM. I think both patterns have their strengths and I've tried to provide some ideas on what those might be. I also contrasted the related composition approaches which aren't necessarily exclusive. I'd love your comments on additional strenghts/weaknesses you've experienced with either pattern.

And if you are building WPF line of business applications and haven't picked up a copy of Teach Yourself WPF, I'd definitely recommend it. This post is also not a thorough representation of the features that Caliburn nor Composite WPF provide - Caliburns Actions are definitely worth a look.

A picture of me

Welcome, my name is Paul Stovell. I live in Brisbane and work full time bootstrapping my own product company around Octopus Deploy, an automated deployment tool for .NET applications.

Prior to Octopus Deploy, I worked for an investment bank in London building WPF applications, and before that I worked for Readify, an Australian .NET consulting firm, where I was lucky enough to work with some of the best in the business. I also worked on a number of open source projects and was an active user group presenter. I've been a Microsoft MVP for WPF since 2006.

11 Jan 2010

Hey Stovie, I think the event driven pattern where the View raises events to communicate to the presenter instead of directly calling it is largely academic. Simply because it looks more loosely coupled doesn't actually add any value IMHO and in fact adds more code and indirection to something which can benefit from more direct invocation. Doing it only because its "loosely coupled" therefore == good I think is just adhering to theory for the sake of it. However I will qualify this by being more web implementaiton biased (and yes I know other MVP implementations use this technique), but again I have not seen it actually add value, just add to the theoretical weighting of the idealistic implementation. Obviously its just my preference, but I think its too easy now to get carried away with loosely coupled indirection without thinking about the why.

11 Jan 2010

I did forget to mention though.... nice article Paul. :-)

11 Jan 2010

Hi Glav,

I should have mentioned in the post that although that's how the view would communicate with the presenter if it really really wanted to; when it comes to WPF the majority of view->presenter communication happens through binding and commands. So in that case the Button would be bound to an ICommand, which when executed would call the delegate on the presenter and there'd be no need for code behind or events.

I guess one advantage it does bring is that the view could be reused by different presenters. It's pretty uncommon but possible.

Paul

11 Jan 2010

Hi Paul,

Great post. Your MVP implementation is very similar to my own variation, which I've called PMVP (Presentation Model-View-Presenter). It's actually quite similar to MVVM; my Presentation Model contains the same UI-oriented properties and events that you'd see in a View Model (data sources, bindable commands, property change notifications, etc.), but the presentation logic is contained within the Presenter rather then being rolled into the View Model. I never liked the idea of cramming the presentation logic into the VM--this approach just seems cleaner to me.

Mike

Rob
Rob
11 Jan 2010

I really enjoyed reading this post. When we wrote the WPF book, we wanted to add a few things that we weren't seeing in other books at that time. The pattern MVVM wasn't really being discussed broadly at that point, so we chose the more traditional MVP pattern. However, as you note, our implementation is really an MVP/MVVM hybrid. I struggled a bit with how to present this when writing the book. We wanted to give readers a strategy for being successful with WPF that went beyond the mechanics of the framework and encouraged good software practices. But since the book was ultimately a WPF book, we had to be careful how far we went with this (we tried to keep our implementations very simple). You may have noticed sprinklings of other more general software practice info throughout. We also wanted to encourage readers to pursue this subject beyond the covers of our book and learn to apply it in other ways.

Concerning Caliburn, the Presenter classes are very confusing, mostly because of their names. In v2 I have renamed and reorganized these classes, to be more consistent with Jeremey Miller's Screen Activation Lifecycle patterns. This is, after all, the purpose of these classes. The main difference between screen activation and region injection is perspective. Regions are view-first. Screen activation is model-first. Don't be fooled by event aggregator. You are just as coupled using regions as using Screen composition. With regions you are coupled to strings and with screens you are coupled to interfaces. Pick your poison ;) I can say that in practice we haven't had any issues with Screen composition. It has simplified a lot of problems. For an intersting example, have a look at NHProf. The entire UI is composed in this fashion.

12 Jan 2010

Just a question / opinion on the ShowViewRequest event. I've struggled in the past with the semantics here of using an Event to get the next view up - events are broadcasts that something has happened for example ContactDetailsViewWasShown but in this case you want something to happen and more importantly expect it to. After all if nothing is subscribing to the event (which could happen if something is shifted to another module which is no longer present) then nothing happens when the button is clicked - this happened to me in a CAB application and we

I've always preferred this to be a direct method invocation - _contactUIService.ShowContactDetails(12345). followed by an event (if necessary) - ContactDetailsWasShown().

12 Jan 2010

Hi Graeme, I see where you're coming from. Having a service is possibly easier to mock too and is a little more explicit (and you can probably debug it easier). The benefit the event has is that there's only needs to be one subscriber and event definition - you don't have to create another service for each UI you build.

I could see perhaps something like this:

_navigationService.ShowView(typeof(IContactDetailsPresenter), "ContentPane", new ContactDetailsParameter(12345);

The thing I like about events is they make less assumption about what the downstream service will do. I don't like the presenter dictating the next navigation action - the event is a little more subtle "this happened, you might wish to navigate" as opposed to a forceful "do this" action. In the end I guess it's just semantics, there are assumptions either way.

Obaid
Obaid
23 Sep 2010

Scenario is i.e. assume the setup property inspector in Blend 4, when the user types property names in search textbox, the lower view changes for every keystroke. I want to implement this scenario by doing a TwoWay databinding to ViewModel's SearchText property and have presenter do the searching for me and eventually update the UI. In this setup ViewModel should notify presenter when SearchText is changing. This is not present in the pattern discussed. Or I'm missing something. Your thoughts will be very helpful.

Obaid
Obaid
23 Sep 2010

Download code link is not working. Is there any other place to get the sample code for the above discussion.

Juan
Juan
05 Oct 2010

Sample code link is down

16 Nov 2010

Nice article. Unfortunately the code link is still broken...