Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Model View Presenter with WPF and Unity Container

3.87/5 (8 votes)
1 Jan 2009CPOL5 min read 67.9K   1.4K  
This article demonstrates using a model view presenter (MVP) pattern in a sample program.

Introduction

This article demonstrates using a model view presenter (MVP) pattern in a sample program. I analyzed some articles on MVP and found that each article is different from others in some way or the other. This might be due to the availability of variants and approach to implement this pattern. This article does not focus on details, rather it just explains the program flow. For more details, please refer to the link below:

(Microsoft MSDN site has many useful articles on MVP.)

Note: The implementation of the pattern is based on Unity application block. It is used for IoC (Inversion of Control) and Dependency injection needs of the application. There are other ways to achieve the same.

Basics

Model View Presenter is a design pattern and considered to be a derivative of the Model-view-controller. It aims to facilitate test-driven development and helps separate the responsibilities for the visual display and the event handling behaviour of the system into different classes.

A view class manages the controls on the form, and it forwards events to a presenter class. The presenter contains the logic to respond to the events, and in turn, manipulates the state of the view. The presenter class uses the model (business entitles) to determine how to respond to the events.

When the model is updated, the view also has to be updated to reflect the changes. There are several approaches to do this. The following two approaches are widely used:

  • Passive View
  • Supervising Controller

CustomerInfoObserver

Figure-1: Supervising Controller

In Passive View, the presenter updates the view to reflect changes in the model. In Supervising Controller, the view interacts directly with the model to perform simple data-binding that can be defined declaratively, without presenter intervention. The attached sample example uses the Supervising Controller variant.

Prerequisite

This example uses WPF and Unity Application Block (Enterprise Library 4.1) as IoC container.

  • WPF – Presentation technology
  • Unity IoC Container – This container can be used to provide dependency injection.
  • Basic knowledge of Data Binding technique

Program Flow

A very simple example is used here for demonstration purpose. However code can become very complex when heavy controls are used with data binding.

The form in our example contains a textbox to hold a customer name and a button AddCustomer to add a new one. The project contains two folders Common and Customer. Common folder contains base classes and Customer folder has the Model, View and Presenter classes. These represent the Customer.

Creating and Initializing Unity IoC container

Class ContainerAccessor is used to create the Unity Dependency Injection Container. We can configure IoC container to read type mappings (Interface and class implementing the interface mapping) from configuration file. As a sample case, I have declared two types in configuration file under <unity>section.

XML
<unity>
    <containers>
      <container>
        <types>
          <type
            type="CustomerInfoObserver.ICustomerDataSource, CustomerInfoObserver"
            mapTo="CustomerInfoObserver.CustomerDataSource, CustomerInfoObserver"/>
          <type
            type="CustomerInfoObserver.ILogger, CustomerInfoObserver"
            mapTo="CustomerInfoObserver.Logger, CustomerInfoObserver"/>
        </types>
      </container>
    </containers>
  </unity>

Similarly we can register any services in the configuration file to be used horizontally from across the application. For example, Microsoft Enterprise Library, Data Access Service, etc. Container will resolve / create instances automatically for defined types and inject dependent objects that have been requested by them through constructor.

The following code snippet creates the instance of container and configures it by reading unity section from configuration file.

C#
_container = new UnityContainer();

//---Runtime Type binding - Read the Type mappings from unity 
//container section from configuration file.
UnityConfigurationSection section = 
	(UnityConfigurationSection)ConfigurationManager.GetSection("unity");

section.Containers.Default.Configure(_container);

Unity IoC and Model-View-Presenter

Base Class as a Generic type for All Views – BaseView

In general, view gets the instance of presenter class and invokes methods to delegate the work. Since taking the instance of presenter in every view is common, we will write it in the base class called BaseView. BaseView is defined as generic type and receives two parameters, one is view type and another one is presenter type. The base class uses IoC container to resolve the presenter instance and injects required services to it.

C#
public class BaseView<TView, TPresenter> : System.Windows.Window
    where TPresenter : BasePresenter<TView>
    where TView : class
{
    public TPresenter Presenter { get; set; }

    public BaseView()
    {
        ContainerAccessor containerAccessor = new ContainerAccessor();
        UnityContainer container = containerAccessor.GetContainer();

        if (container == null) throw new InvalidOperationException
                ("Cannot find UnityContainer");

        Presenter = container.Resolve<TPresenter>();
        Presenter.View = this as TView;
    }
}

The base class inherits System.Windows.Window that enables all derived classes from BaseView to be a window.

Derived View Class – CustomerView

The WPF window (view) derives from BaseView base class, which is doing all the work to inject the Presenter into the View using Unity. While implementing the mandatory interface ICustomerView, CustomerView is also specifying which presenter is to be used through generic parameters.

In Model-View-Presenter pattern, presenter will always use interface to communicate with view.

C#
public partial class CustomerView
    : BaseView<icustomerview, />, ICustomerView

You will also have to change the XAML code associated with CustomerView class as below. This modified code removes the inheritance from System.Windows.Window and has it derived from CustomerInfoObserver:BaseView. See the changes required in xmlns namespace.

XML
<CustomerInfoObserver:BaseView x:Class="CustomerInfoObserver.CustomerView"
    x:TypeArguments="CustomerInfoObserver:ICustomerView, 
		CustomerInfoObserver:CustomerPresenter"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:CustomerInfoObserver="clr-namespace:CustomerInfoObserver"
    Title="Window1" Height="255" Width="341"
    >

The Window/View receives the Click Event of the AddCustomer button and passes the request to the Presenter. In this case I am delegating requests to the presenter. I could have just as easily had the Presenter class subscribe to various View Events.

C#
private void btnAddCustomer_Click(object sender, RoutedEventArgs e)
{
    Presenter.OnAddCustomer(txtCustomerName.Text);
}

Base Class as a Generic type for All Presenters – BasePresenter

Being the base class for every presenter exposes view through property named View.

Derived Presenter Class – CustomerPresenter

This class handles all the requests received from CustomerView (view). On initialization, presenter passes model object to the view by calling interface method SetCustomerModelAsDataContext().

C#
View.SetCustomerModelAsDataContext(_customerModel);

CustomerView class sets this model as DataContext for the entire window, so all child UI elements will use the same DataContext for binding. The syntax for data binding is given below. The code is available in CustomerView XAML file.

C#
Text="{Binding Path=CustomerName, Mode=TwoWay, UpdateSourceTrigger=LostFocus}

Using data binding in MVP saves much coding effort and facilitates synchronization between Data Model and View.

Model Class – CustomerModel

Class CustomerModel contains business data and that is exposed through properties. Since we have used data binding feature and associated windows element (textbox - txtCustomerName) with CustomerModel property (CustomerName), change made to the txtCustomerName textbox will immediately reflect into CustomerName property. In order to reflect the change back to the screen, CustomerModel class has to implement INotifyPropertyChanged interface. INotifyPropertyChanged interface will notify the view that Model value has been changed and can update the UI.

INotifyPropertyChanged interface is also implemented by BusinessEntity class in Embassy.

Note: The code is provided with the attached zip file.

History

  • 25th December, 2008: Initial version

License

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