Posted in:

One of the most popular sections of my Windows Forms Best Practices course on Pluralsight was the section where I described the Model View Presenter pattern.

It seems no one is interested in MVP these days, because if you’re doing server side web development you’ll probably be doing MVC, and if you’re writing WPF apps or SPAs (e.g. using Knockout.js), then you’re likely to be doing more of an MVVM pattern, where you use data-binding to communicate between the view and the model, and a “view model” to bridge the impedance mismatch between the two. Both these patterns are great, but I think the MVP pattern does still have something to offer for certain types of application.

So what is the Model View Presenter pattern, and why use it? Well basically, in Model View Presenter, you start off by making each of the UI components (in WinForms that would be user controls and forms) implement a view interface.

View Interfaces

The view interface should contain properties that allow the state and content of the controls in the view to be set and retrieved. It may also include events to report back user interactions such as clicking on a button or moving a slider. The goal is that the implementation of these view interfaces is completely passive. Ideally there should be no conditional logic whatsoever in the code behind of your Forms and UserControls.

Here’s an example of a view interface for a new user entry view. The implementation of this view should be trivial. Any business logic doesn’t belong in the code behind (and we’ll discuss where it does belong next).

interface INewUserView
{
    string FirstName { get; set; }
    string LastName { get; set; }
    event EventHandler SaveClicked;
}

One nice benefit of this approach over MVVM in WPF is that you don’t have to create complicated “behaviors” just to do simple things like setting the focus to a particular control on the form, or asking a listbox to scroll an item into view. Just add methods to do that onto your view interface, and the implementation can manipulate the UI component directly.

Presenters

Once you have made all your views passive and implement interfaces, you need something that will implement the business logic of your application and control the views. And these are called “presenter” classes.

The presenter’s job is to instruct the view what data to display. The view is also allowed to communicate back to the presenter. In my example above it does so by raising an event, but alternatively with this pattern your view can make direct calls into the presenter.

What is absolutely not allowed is for the view to start directly manipulating the model (which includes your business entities, database layer etc). If you follow the MVP pattern, all the business logic in your application can be easily tested because it resides inside presenter or other non-UI classes.

Obviously you do run the risk of your presenters getting overly complicated. In a real application, they will likely depend on other services and helpers which are doing the bulk of the business logic, leaving the presenter class to focus simply on “presenting” the data to the view, which is what it’s name implies.

Why Use It?

So what are the benefits of using? Well, one thing I like about this pattern is that it is very simple. It’s got a clear division of responsibilities and a new user coming to the codebase can easily understand and extend the pattern.

It also protects you from putting business logic in code behind, which is one of the main reasons a lot of WinForms applications are not easily testable and maintainable. And as I demonstrate in my Pluralsight course, it makes it very easy to migrate to WPF, since all you would need to do is implement the view interfaces again – all your business logic is reusable.

Demo Code

In my Pluralsight course, I demonstrated how to refactor a badly written Windows Forms apps into a better state. Unfortunately, time did not permit me to show anything more than the beginnings of an MVP pattern. But since so many people have asked to see a more developed example, here’s the demo application from that course, but refactored to use MVP more extensively. Of course, this is still a small application – for a real enterprise app I’d almost certainly introduce an IoC container to construct the views and presenters, and add in a framework for navigating between views. But hopefully this serves to give you some ideas for how you can begin to apply this pattern in your own applications.

Want to learn more about Windows Forms? Be sure to check out my Pluralsight course Windows Forms Best Practices.

Comments

Comment by Leszek Salford

Hi,
Thanks for sharing.

Leszek Salford
Comment by Juraj Gulovič

Hi Mark.
Thank you so much for complex example, it is very helpful. I've followed your steps some time ago on Pluralsight and now is again time to use your best practises. However, it is not intended to be ready to test presenters in this particular demo from separate test project? Why are your interfaces and classes marked as internal?

Juraj Gulovič
Comment by Mark Heath

yes, I didn't make any unit tests in this sample, but if I had, I would have made those classes public (I used to use InternalsVisibleTo, but I've moved away from that approach now)

Mark Heath
Comment by Geovani Martinez

Hello Mark,
I went thru you plural-sight course and one question that been nagging at me is, what is the proper way to access the form properties such as .Icon .Text, .KeyPreview etc.. when using the MVP pattern, right now I'm using overrides but not sure if its the right way (since it sometimes bloats up the view, see attached example). Any input would be greatly appreciated.
https://uploads.disquscdn.c...

Geovani Martinez
Comment by Mark Heath

hi Geovanni - sorry for the delay getting back to you. In this scenario I'd probably just give the property a different name or create a SetIcon method or something on the view interface, so that the presenter can just call to that method, and then in the view it can delegate on to the underlying .Text or .Icon property

Mark Heath
Comment by David Raasch

Thanks for posting this! Just went through most of your Pluralsight course. (I plan on getting back to the rest of it later. But for now, everything up through the MVP module interested me.)
I inherited a monolith Winforms application a few years ago.... as a team of one. And now I'm on a new team, leading two additional people in developing this thing. And we've been given time to finally go back and try to clean up the code. It's Main is 19k lines long. It's primary application instance class is 6k lines long. There are roughly 30 child forms.
And there are basically no unit tests.
So, I'm planning how we're going to break this thing up. As much as I enjoy seeing the entire app UI at once in Main, so I can handle "visual real estate issues" more easily, breaking things apart into UserControls seems to be what I'm destined to have to do. (The app consists of three columns... basically a splitcontainer. And then two of the columns consist of tabs and subtabs. Most tabs have their controls divided by splitcontainers. The app "remembers" the locations of the splitters, which makes users happy when they adjust /resize things.)
Are there any recommendations you would have for separating things out like tabs/tabcontrols and splitcontainers within them? Any "gotchas" I should watch out for?

David Raasch
Comment by Mark Heath

Sounds like there is quite an obvious first step of breaking up your application into UserControls for each of the three columns, and then one for each of the tabs/subtabs. The main gotcha would be tight coupling between components - when everything is in one MainForm, you can affect any other part of the UI from any other part. So you might need to introduce either a pattern like MVP or some kind of event aggregator to decouple different UserControls from each other.

Mark Heath
Comment by fretelweb

Do you have the course in Udemy? Its my favorite platform to learn.

fretelweb
Comment by Mark Heath

sorry, this course is only on Pluralsight

Mark Heath
Comment by Steven O

Hi Mark,
Thank you for sharing. This pattern has significantly helped my WinForm design. I am having an issue, however, with the Event Aggregator you included in this project. When trying to unsubscribe from an event subscription, the action does not get removed from the List<object> subscribers, so the object remains as a subscriber, even when I dispose of it's parent object. Can you provide any insight as to why the action (subscriber) is not being removed?

Steven O
Comment by Shandy Sawyer

Thank you for sharing this, its a huge help for the community, since legacy code is always out there! Two questions,
1. You made a comment in your code about "for now, keep presenters alive with Tags". I'm assuming this where a IoC container would instead do the work of keeping them alive?
2. You mention a framework for navigating between views. Could you elaborate on what you're referring to?

Shandy Sawyer
Comment by Da Best

Mark,
Thanks for this article. It's helped a lot in dealing with large Winforms and getting them under control.
But the comment "for now, keep presenters alive with Tags", how would your code look, if you didn't use the Tag property? What changes would have to be made?

Da Best
Comment by Mark Heath

It's been a very long time since I wrote this article, and have mostly moved away from WinForms development, so not sure I can give a great answer. I think to get away from Tags I'd either introduce some kind of view management framework, or maybe create a dedicated property to hold the presenter.

Mark Heath
Comment by Mark Heath

An IoC container can manage object lifetimes, but it doesn't necessarily do so. For example it holds onto singletons, but can also just create an object and hand it over to you, so it won't manage the lifetime.
In terms of a framework for navigating, its been a long time since I wrote this article, but I think I just meant creating some kind of "ViewManager" class that has a concept of what the current view is and can be sent messages to navigate to another view.

Mark Heath