This post is in a series of posts on the MVP framework. The first entry can be read here.
In the framework due to release by the end of 2010, the Nucleo MVP framework provides several options for setting up the presenter. First, the presenter interface has the following implementations:
IPresenter
IPresenter<TView>
IPresenter<TView, TModel>
Each of these has a BasePresenter class equivalent as in the Nucleo.Mvp DLL:
BasePresenter
BasePresenter<TView>
BasePresenter<TView, TModel>
It's the simplest to inherit from one of the base classes, but interface implementation works too.
The presenter knows about the view through the interface, but doesn't know the exact implementation. The presenter also has a reference to a context. The PresenterContext property mimics the ASP.NET MVC approach to using services within the infrastructure (such as HTTP context). However, BasePresenter doesn't know about HTTP context, so the default implementation does not include this. The default implementation includes the ApplicationContext object, a core way to serve up references (similar to a Dynamic Injection container).
This is where the BaseWebPresenter comes in, defined in the Nucleo.Web.MVP DLL. The BaseWebPresenter class mimics the approach of BasePresenter, and provides web-specific add-ons such as HTTP context references and more. Additionally, it leverages this through a completely generic interface of type IWebContext. You can certainly use HttpContext if you are more comfortable, that reference is included too.
Let's look at a sample presenter:
public class CreateCustomerPresenter : BaseWebPresenter<ICreateCustomerView> { #region " Constructors "
public CreateCustomerPresenter(ICreateCustomerView view) : base(view) { view.Cancelled += delegate(object sender, EventArgs e) { this.ClearForm(); }; view.Loaded += delegate(object sender, EventArgs e) { this.LoadCustomer(); }; view.Saved += delegate(object sender, EventArgs e) { this.SaveCustomer(); }; view.ViewAllCustomers += delegate(object sender, EventArgs e) { this.CurrentContext.Context.Navigation.NavigateToUrl("~/Views/ViewCustomers.aspx"); }; }
#endregion
#region " Methods "
public void ClearForm()
{
this.View.FirstName = "";
this.View.LastName = "";
this.View.AccountNumber = "";
}
public void LoadCustomer()
{
this.View.FirstName = "John";
this.View.LastName = "Doe";
this.View.AccountNumber = "12345";
}
public void SaveCustomer()
{
//Pass saved information to the data layer
this.ClearForm();
this.View.ShowMessage("The customer has been saved.");
}
#endregion
}
Here the presenter attaches to the view's events. The view notifies the presenter when something happens through an event. The event is controlled by the view (such as a button click), so the presenter is essentially reading and reacting appropriately. Note the presenter does the heavy lifting of the form.
It is within the presenter that you have to determine whether you want to leverage storage containers like session, cookies, cache directly from the presenter, or create a wrapper for them. A wrapper gives you the advantage of not truly knowing what the underlying storage mechanism is (encapsulation) and allows you to provide a fake at runtime for testing purposes. This is also built into the framework, and we'll see more examples of this later.