Click here to Skip to main content
Click here to Skip to main content

WinForms Model View Presenter

By , 11 Aug 2008
 

Introduction

The terms "Model View Controller" and "Model View Presenter" (MVP) are used to describe patterns that have been in use for some time in other technology areas but have recently come to the fore in the C# world.

The Model View Presenter is a derivation of the Model View Controller pattern. With modern ides such as Visual Studio inserting event handling into what we refer to as the view, it makes sense to leave them there rather than trying to implement them on a controller.

I struggled to find a simple MVP example on the web that was geared towards C# WinForms, and after reading Bill McCafferty's excellent article on MVP within ASP.NET, I decided to throw my hat into the ring.

I'm going to concentrate on the code. For a background on MVP, I suggest you try this link:

Why MVP?

The Model View Presenter pattern is designed to abstract the display of data away from the data and associated actions (e.g., saving the state). This, in theory, should make testing easier and more relevant, and remove the tight coupling typically found between data and forms within the Windows environment.

The View

The View is a user control that inherits from System.Windows.Forms. Its role in life is to display whatever data we are interested in. It contains no logic other than raising an event should the data change and any processing particular to the View such as closing itself happens. It doesn't care if anybody is listening to the event, it simply raises the event and has fulfilled its purpose. The View implements an interface that exposes fields and events that the Presenter needs to know about.

public class UserView : Form, IUserView

The Model

It is a representation of the data being manipulated. In my simple example, this a user object. The Model should implement an interface (IUserModel) that exposes fields that the Presenter will update when they change in the View.

public class UserModel : IUserModel

The Presenter

The Presenter marries the View to the Model. When first called, it updates all the properties of the View to correspond to the Model. Furthermore, it binds the View's events to methods in itself. Typically, the Presenter will update the Model based on changes in the View. Once a user has finished making changes in the View, the Model should be in sync and will be saved down correctly. The Presenter does not require an interface.

public UserPresenter(IUserModel model,IUserView view)
{
    this._model = model;
    this._view = view;
    this.SetViewPropertiesFromModel();
    this.WireUpViewEvents();
}

In my example, I use Reflection to iterate through the properties of the View / Model and update the corresponding field. Reflection is slow, but I haven't experienced any tangible slow down in any of my Windows apps yet - it would be easy to pass through a reference to the specific property being updated if speed starts to become an issue.

Putting it Together

IUserModel model = new UserModel();
IUserView view = new UserView();
new UserPresenter(model,view);
view.Show();

The code to get the ball rolling is simplicity itself, as shown above.

Testing

The example with this article includes some tests. Because our Presenter expects interfaces as opposed to concrete objects, it allows us to perform dependency injection with stubs and mocks, should we choose.

[Test]
public void DoesViewCorrespondToModel()
{
  StubView stub = new StubView();
  new UserPresenter(this._mock, stub);

In my tests, I have a StubView that implements the IUserView interface. I then instantiate a mock object representing the Model and perform testing on that. My tests check that the View shows what's in the Model and that the Model is updated when the View changes. You would, of course, include more tests in a real world project.

My stub implements Event Mocking, e.g.:

public void FireDataChanged()
{
    if (this.DataChanged != null)
    {
        this.DataChanged(null, EventArgs.Empty);
    }
}

From within my test, I simply call 'FireDataChanged' to recreate what would happen when a user changes any of the data in my View from within the application.

A Word on DataBinding

You may be wondering why I go to the trouble of implementing code in the Presenter to update the Model / View when Microsoft kindly provides us with databinding technology to bind data to Windows controls. The great thing about databinding is that it removes the need for having to write code in every Presenter to take care of the state, thus speeding the development cycle.

The problem with databinding is that it breaks our encapsulation by tightly coupling the 'View' to the data. Also, it cannot be tested from within an NUnit environment. However, one still needs to write laborious code within the Presenter to keep the Model in sync with the View. I hope that the code example I have provided you with that uses Reflection will ease this pain. Simply expose the data you require in the View and Model interfaces, and it should all be taken care of for you.

I am not a pattern zealot; you may find that given time constraints and the nature of a task you need to perform, a tightly bound view using databinding is the best option - however, I would encourage the abstraction of logic from presentation and the use of tests wherever possible.

Refactoring the Interfaces

It became apparent in the development of this article that a lot of property definitions are shared between the IView and IModel interfaces. In fact, every editable data property exposed on the Model needs to be implemented on the View; you may, therefore, like to consider implementing an additional interface called ICommonFields that is implemented by both IModel and IView. The benefit of this approach is that one only needs to add a new property to a single interface for the compiler to insist on its implementation in both the Model and the View.

Finally

Using MVP within WinForms is a learning curve, and I am keen to hear constructive criticism from anyone who thinks the example I have provided can be improved. By sharing knowledge, we all gain.

Credits

The MVP pattern has been developed by many coders over a long period of time. Martin Fowler presents that knowledge in a nice concise form on his website (link at the top of the article).

Thanks to Bill McCafferty for investing so much time in the article he wrote about MVP in ASP.NET (link at the top of article) which inspired me to submit a WinForms focused article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

cgreen69
Software Developer (Senior)
United Kingdom United Kingdom
Member
A .net devotee specialising in Object Orientated web development for financial institutions in Europe. When not working can normally be found at a bar within walking distance of the office.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralNice one for a startermemberernestohari7 Oct '11 - 0:14 
I was looking for a simple example to start with. After frightening from msdn samples this was good hope.
QuestionIs it really necessay to use reflection in the presenter?memberkapil Sinha11 Aug '11 - 21:27 
Is it really necessay to use reflection in the presenter? Is it needed just to ensure loose coupling?
GeneralOn databinding vs. decouplingmemberArtem Smirnov20 Aug '08 - 9:07 
I think decoupling is overrated. You decouple, after all, in order to make your code more maintainable. When you do it just for the sake of decoupling, your code can quickly become a mess of services, interfaces, and abstract factories, just to decouple a call to MessageBox.Show(). Back to the article, I think that winforms databinding is much better maintainable than the reflection method presented here. For example, how do you implement binding a grid to a list of items? Another problem is the requirement that the model properties correspond to these of the view -- isn't it just another form of coupling?
 
On the other hand, you can easily decouple your view from your data if you use a BindingSource object. In my opinion, this is much better maintainable, since you don't have to change your view or model interface whenever you add/remove a property to/from your class. For example, you may pass an instance of the Order class to your view. In the View code, this instance becomes the data source of the corresponding BindingSource object. Adding a property to this class doesn't change the interface, just the implementation (you might want to add a textbox or a grid column).
 
This is, of course, just another flavor of MVP (which Fowler calls Supervising Controller).
QuestionIUserViewmemberMember 308313919 Jun '08 - 17:29 
Why there is no error during the compilation of MVP project when the Show() method of IUserView is not implemented in the UserView class?
AnswerRe: IUserViewmemberke4vtw10 Sep '08 - 17:53 
I haven't investigated this closely, but I would assume that IUserView is implemented either on a WinForm or a WebForm, both of which already have a Show() method that would fulfill the contract.
GeneralModel-View-Presenter frameworksmemberOleg Zhukov24 Apr '08 - 11:27 
Good and clear explanation! I want to notice though that in the real-world conditions it is better to use some MVP framework, such as MVC#. It automates many of the tasks described above, and simplifies MVP pattern usage.
 
--
Oleg Zhukov

QuestionWhy is your UserPresenter in the Library namespace but in the MVP folder? [modified]memberDao-Huy Hua15 May '07 - 4:02 
I was trying to start a new project following a MVC sample and I found your code quite interesting even if it is a MVP. Seriously, it's the first time I heard about MVP and I quite like the concept after reading a bit on the subject.
 
By reading your code, I have this questionning: why is your UserPresenter in the Library namespace since it is in the MVP folder? Is it intentional?
 

-- modified at 10:41 Tuesday 15th May, 2007
GeneralArticle UpdatememberMarkus Klieber17 Apr '07 - 7:34 
Hi Chris,
 
i like your article, but i think you should have to update you description about the MVP. Martin Fowler devided MVP into two new patterns. As i see you described the so called "Passive View" pattern.
 
In original MVP described in the "Smalltalk" language there is still a communication between the View and the Model like in the MVC pattern.
 
I think this is a bit confusing, because the first time i read your article i thought this is the original MVP, but what is "orignial" with all those variants of MVP...
 
kind regards
Markus
GeneralWhy not just use a generic presenter and pass property namemembernji7812 Apr '07 - 14:28 
I'm just curious, but it seems this single presenter can be extended at reused.
Why not just use a generic presenter that implements SetViewPropertiesFromModel(),
SetModelPropertiesFromView() and have it handle every model.
 
Also, why not just pass the Property Name to _view_DataChanged rather than looping thru the whole PropertyInfo collection to find values that have changed?
GeneralRe: Why not just use a generic presenter and pass property namemembercgreen6915 Apr '07 - 9:13 
Hi and thanks for your question.
 
I'm not entirely sure I understand your first question but here goes; A generic presenter could work in theory assuming that all the presenter ever has to do is copy values to / from the model. Typically this isn't the case, real world apps have presenters with more logic in therefore I don't think a generic presenter would be suitable.
 
Your second statement is a good suggestion assuming that we want to react straight away to a change. The code I have included with the article allows all values to be synchronised when a particular event occurs, e.g the user presses save and all values from the view need to be set on the model prior to saving.
 
I hope that anwsers your questions,
 
Chris

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 11 Aug 2008
Article Copyright 2006 by cgreen69
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid