MVP pushing data to the view

Published by on
Tags:

The other day I was chatting to my friend and we were discussing the model view presenter (MVP) design pattern. We got onto the discussion of display collections of items in the view. It gave me a few thoughts about the different techniques that could be used. Each technique has some advantages and disadvantages and I hope to discuss each of these in turn.

We are going to have a presenter that performs a simple task. I want it to display a list of products to the user. I am going to keep the presenter as simple as possible; the constructor takes no arguments and the class consists of a single Init method that starts the whole process off. When working with MVP I prefer to have an Init method which I will call to kick the whole process off.

So my presenter has this simple template:

     8     public class ProductListPresenter

    9     {

   10         IProductListView _view;

   11         IProductService _service;

   12 

   13         public ProductListPresenter(IProductListView view, IProductService service)

   14         {

   15             _view = view;

   16             _service = service;

   17         }

   18 

   19         public void Init()

   20         {

   21             //TODO: pass the list of products to the view.

   22         }

   23     }

 I am going to use a simple Product entity to represent each product. The class is as follows:

    8     public class Product

    9     {

   10         public string Name { get; set; }

   11         public double Price { get; set; }

   12         public string Description { get; set; }

   13     }

The first method I am going to look at is passing an array of Products to the view and then letting the view deal with how it iterates over the collection of Products. The interface looks like: 

    8     public interface IProductListView

    9     {

   10         public Product[] Products { get; set; }

   11     } 

The presenters Init method can then pass the list of products can be passed directly into the view from the service (yes this is a very simplistic example). 

    19         public void Init()

   20         {

   21             _view.Products = _service.GetAllProducts();

   22         }

 I can now take advantage of some of .Net’s web controls. For example I want to use the System.Web.UI.WebControls.Repeater control to display product information. In the concrete view I can simple the Products property directly to the Repeater controls data source property:

   15         public Product[] Products

   16         {

   17             get

   18             {

   19                 return (Product[])_productRepeater.DataSource;

   20             }

   21             set

   22             {

   23                 _productRepeater.DataSource = value;

   24             }

   25         }  

As you can see this is a very quick way wiring views and presenters but has the disadvantage where the get accessor has to cast from object to the Product array. However we could remedy this by removing the get accessor from the IProductView interface. Another disadvantage is that this method does not give the presenter control over what information about the product is displayed by the view. For example if the product contains an additional field called “ConfidentialInformation” the developer implementing the view would have access to this field and could accidentally render this data to the user. This really isn’t a problem if the developers working on the views have good spec’s to work from but might cause a problem if you are expecting a third party to develop the views. Another lesser issue is exposing entities from the domain to the view which you may or may not wish to do depending on how strict you want your layer separation to be.

Another method is to have your view expose a method which the presenter calls to render the list to the user. For the  The IPresenterView would change to the following:

    8     public class IProductListView

    9     {

   10         void RenderProduct(string productName, double productCost);

   11     }

The presenters Init method then changes to:

   19         public void Init()

   20         {

   21             foreach (Product product in _service.GetAllProducts())

   22             {

   23                 _view.RenderProduct(product.Name, product.Price);

   24             }

   25         }

  

This method gives complete control over what the view renders to the user but has the disadvantage that it makes using the inbuilt .Net web controls more complex; for example we could not simple wire straight into the data source of the render control like we did before. However we can create a simple web control to do something similar:

 

   10     public class ProductView : HtmlControl,  IProductListView

   11     {

   12         public ProductView() : base("ul") { }

   13 

   14         #region IProductListView Members

   15 

   16         public void RenderProduct(string productName, double productCost)

   17         {

   18             HtmlGenericControl listItem = new HtmlGenericControl("li");

   19             listItem.InnerText = string.Format("{0} - {1:C}", productName, productCost);

   20             this.Controls.Add(listItem);   

   21 

   22         }

   23 

   24         #endregion

   25     }

  

   

As yet I am unsure which technique is better and I think both have the benefits. I find that for speed and simplicity the first technique works better and I can trust the developers of the views not to implement incorrect properties, however there is still something about it that makes me feel uncomfortable. Let me know your thoughts and what other techniques you might have for handling collections of items.

Add comment

 

Projects

Have you read?

SharePoint SPSecurity.RunWithElevatedPermissions



Blogs by date