The Model View Presenter pattern with .NET.

I had a request from one of my blog’s reader (Bastien) that I can’t skip. Last week he asked me to write a short article on how to implement the Model View Presenter with Windows form. So let’s skip for a while my series of articles about Prism and let’s see what is the MVP and how it should be implemented.

The Model View Presenter pattern.

The definition of the model view presenter pattern can be found in many web site, let’s use the classic definition provided by MSDN. (This is an interesting article that explains the MVP).

Model-view-presenter (MVP) is a user interface design pattern engineered to facilitate automated unit testing and improve the separation of concerns in presentation logic.
1) The model is an interface defining the data to be displayed or otherwise acted upon in the user interface.
2) The view is an interface that displays data (the model) and routes user commands (events) to the presenter to act upon that data.
3) The presenter acts upon the model and the view. It retrieves data from repositories (the model), persists it, and formats it for display in the view.

There are two different types of MVP implementation: the MVP passing view and the MVP supervising controller. The main difference from these two types of UI patterns is that in the passive view, the view doesn’t know anything about the model and the presenter is in charge of “advise the view” that something happened. In the second implementation, the view knows the model for the basic binding and the presenter is used only when the view requires complex UI manipulation.

image

Personally I completely disagree with the second approach, because the layers are not really recyclable, and a change in the model constraint the developer to change also the view … Frown

The sample model.

As I usually do, you will find a sample application at the end of this article. So let’s start building a very simple fake model that will be the “famous” Customer-> Orders.
First of all we need a new Visual Studio solution and we need to structure our application into 3 layers. Of course I am going to create just one project with 3 folders but usually you should have 3 different .dll (UI, Presenter, DAL, Model …) maybe more than 3. tongue-out

image

As you can see from the model we have our classic DomainObject class, abstract, that represents a domain object, so in my case I want to know for each object, its unique id and if it’s valid.

Then we have a Customer, that can have one or more address, a List of Order and for each Order a list of Order Items.

The view and the windows forms.

Using the Windows form approach, our view is what we are showing to the user. So in this case our view will be a Windows form. We have 2 views, one is an overview of all the available customers, and the second one is specific to an order.

All available Customers.

image

All available Order for a specific Customer.

image

Now we need to create a generic implementation of the relation View-Model-Presenter and try to recycle some code. This is my idea: we will have a base view that will expose the view name and a couple of methods, then each view will inherits the base one. In this case the view will expose directly the domain entity, but this should not be done in production, I would suggest to use the DTO.

image The implementation of the Generic View.

Under the folder views, we need to create a new interface, IBaseView:

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: 
  6: namespace ModelViewPresenter.View {
  7:     public interface IBaseView {
  8:         string Name { get; set; }
  9:     }
 10: }

Now we can start to implement the CustomersView that will represent the information we have in the Customer window:

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using ModelViewPresenter.Model;
  6: 
  7: namespace ModelViewPresenter.View {
  8:     public interface ICustomersView : IBaseView {
  9:         Customer SelectedCustomer { get; }
 10:         IList<Customer> Customers { get; set; }
 11: 
 12:         string FirstName { set; }
 13:         string LastName { set; }
 14:         string BirthDate { set; }
 15:         string Address { set; }
 16:     }
 17: }

In this view we have two different types of information. First of all we have an IList of Customer that will represent our data source for the main grid, and a single instance of type Customer that will represent the selected Customer in the grid.

Then we have some basic data type information that we will use to render the current selected Customer in the grid. These information will be filled by the presenter. Unfortunately in my case the view knows the model but you can avoid that using a Dto.

A fake repository.

Of course we usually have a DAL that read the data from the Db and translate these information into a collection of entities, or better, inside our Domain Model. For this application I have created a simple repository structure just to show you how I implement the MVP pattern using generics.

The base repository:

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: 
  6: namespace ModelViewPresenter.Model {
  7:     public interface IBaseRepository {
  8:         void Initialize();
  9:     }
 10: }

And then the concrete implementation for our views:

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: 
  6: namespace ModelViewPresenter.Model {
  7:     public sealed class CustomersRepository : IBaseRepository {
  8: 
  9:         private IList<Customer> customers;
 10:         
 11:         #region IBaseRepository Members
 12: 
 13:         public void Initialize() {
 14:             customers = new List<Customer>();
 15:         }
 16: 
 17:         #endregion
 18: 
 19:         public IList<Customer> GetCustomers() {
 20:             customers.Add(
 21:             ... ...
 22: 
 23:             return customers;
 24:         }
 25: 
 26:         private void AddAddressToCustomer(Customer customer) {
 27:             ... ...
 28:         }
 29: 
 30:         private void AddOrdersToTheCustomer(Customer customer) {
 31:             ... ...
 32:         }
 33:     }
 34: }
 35: 

My code doesn’t do anything special. It just creates a fake collection of customers and will add 2 orders with some order items for each one.

Use some glue and put all together, the presenter.

Now it’s time to play with a generic presenter that won’t know the view and or the repository. My idea is to do something like this:

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using ModelViewPresenter.View;
  6: using ModelViewPresenter.Model;
  7: 
  8: namespace ModelViewPresenter.Presenter {
  9:     public abstract class BasePresenter<TView, TRepository> 
 10:            where TView : IBaseView 
 11:            where TRepository : IBaseRepository {
 12:         
 13:         protected TView view;
 14:         protected TRepository repository;
 15: 
 16:         public virtual void InitializeView() { }
 17: 
 18:         public virtual void UpdateView(object model) { }
 19:     }
 20: }

First of all we have to declare a generic view and a generic repository. In this way we will pass our concrete view and repository when we will create a new instance of the presenter. Then I have added to simple virtual methods. The first one will “prepare” the view, so we can call it in the load method of the form, or better, in his constructor. UpdateView will receive the selected “instance”  and will update the view.

Let’s try to imagine how the CustomersPresenter should be implemented following this approach:

We declare the class

  1: public sealed class CustomersPresenter : 
  2:      BasePresenter<ICustomersView, CustomersRepository> {
  3: 

The we implement the 2 constructors:

  1: public CustomersPresenter(ICustomersView view) {
  2:  repository = new CustomersRepository();
  3:  repository.Initialize();
  4:  this.view = view;
  5: }
  6: 
  7: public CustomersPresenter(ICustomersView view, CustomersRepository repository) {
  8:  this.view = view;
  9:  this.repository = repository;
 10:  repository.Initialize();
 11: }
 12: 

And then we start to write the code that will override the default methods of our presenter:

  1: public override void InitializeView() {
  2:     base.InitializeView();
  3:     this.view.Name = "All available Customers View.";
  4:     this.view.Customers = repository.GetCustomers();
  5: }
  6: 

and

  1: public override void UpdateView(object model) {
  2:     base.UpdateView(model);
  3:     var selected = model as Customer;
  4:     if (selected != null) {
  5:         this.view.FirstName = selected.FirstName;
  6:         this.view.LastName = selected.LastName;
  7:         this.view.BirthDate = selected.BirthDate.ToShortDateString();
  8:         this.view.Address = selected.FirstAddress;
  9:     }
 10: }
 11: 

When a customer is selected:

  1: public void SelectionChanged() {
  2:     UpdateView(this.view.SelectedCustomer);
  3: }
  4: 

Finally we need to bind all this code in our form, that will “implement” the view and will “know” the presenter. Let’s see.

Bind the view and the presenter to the corresponding windows form.

We have previously created a windows form with some controls and a gridview that will show the available customers. Now, first of all, we implement the view in the form:

  1:     public partial class CustomersView : Form, ICustomersView {
  2: 
  3:         #region ICustomersView Members
  4: 
  5:         public string FirstName 
  6:         {
  7:             set {
  8:                 txtFisrtName.Text = value;
  9:             }
 10:         }
 11: 
 12:         public string LastName {
 13:             set {
 14:                 txtLastName.Text = value;
 15:             }
 16:         }
 17: 
 18:         public string BirthDate {
 19:             set {
 20:                 txtDateBirth.Text = value;
 21:             }
 22:         }
 23: 
 24:         public string Address {
 25:             set {
 26:                 txtAddress.Text = value;
 27:             }
 28:         }
 29: 
 30:         public Customer SelectedCustomer {
 31:             get {
 32:                 if (grdCustomers.SelectedRows.Count > 0) {
 33:                     return (Customer)grdCustomers.SelectedRows[0].DataBoundItem;
 34:                 }
 35:                 return null;
 36:             }
 37:         }
 38: 
 39:         public IList<Customer> Customers {
 40:             get {
 41:                 return (IList<Customer>)grdCustomers.DataSource;
 42:             }
 43:             set {
 44:                 grdCustomers.AutoGenerateColumns = false;
 45:                 grdCustomers.DataSource = value;
 46:             }
 47:         }
 48: 
 49:         #endregion

And now we can assign the presenter to this view in the following way:

  1: protected CustomersPresenter presenter;
  2: 
  3: public CustomersView() {
  4:    InitializeComponent();
  5:    presenter = new CustomersPresenter(this);
  6:    presenter.InitializeView();
  7: }
  8: 

Now, whatever will happen in the form, the corresponding event will call a method in the presenter. In this way we are sure that the form (view) will know only the presenter. Remember that in order to satisfy this prerequisite, you should have a Dto that represents the information you want to show in the view, and not a reference to domain model.

Select a customer:

  1: private void grdCustomers_SelectionChanged(object sender, EventArgs e) {
  2:    presenter.SelectionChanged();
  3: }
  4: 

And show the corresponding orders, a method handled by the presenter that will open a new orders view and show the corresponding orders:

  1: private void grdCustomers_DoubleClick(object sender, EventArgs e) {
  2:     presenter.LoadOrders();
  3: }
  4: 

Conclusions and source code.

The source code of this article is available on my sky drive at this address. The solution is complete so you will find more code, the implementation of the navigator pattern, useful to navigate through the views, and the complete design of the windows form.

This is the address: Raffaeu Visual Studio Sky drive

Remember that you should never share your domain entities inside the view, leave them in the presenter and try to use the Dto and a framework like AutoMapper to do the rest.

This code is trivial just to show you how to implement the MVP using generics, from my point of view. It can be implemented in a better way and it can also be refactored.

I will appreciate if you have suggestions and feedbacks.

If you need another example, like how to use the MVC, or how to implement validation in MVVM, please write me an e-mail, and I will try to satisfy your request.

For now I will continue my series using WPF, Prism and WCF. So stay tuned and Happy new year!

Tags: