Model View Presenters: View to Presenter Communication

31 Jan 2012

Table of Contents:

Communicating from the View to the Presenter is a reasonably straight forward affair. To signal something happening, we use an Event, but one with no parameters. We pass no parameters, as we are not going to be using them anyway, so what is the point is raising an event every time with OkayClicked(this, EventArgs.Empty)?

To get around this, we define a new event type, so that we can get rid of our redundant parameters:

public delegate void EventAction();

In the View we define our events:

public interface IEmployeesView
{
    event EventAction OkayClicked;
    event EventAction CancelClicked;
}

And in the Presenter we hook up the events:

public class EmployeesPresenter : IDisposable
{
    private readonly IEmployeeView _view;

    public EmployeesPresenter(IEmployeesView view)
    {
        _view = view;
        _view.OkayClicked += OnOkayClicked;
        _view.CancelClicked += OnCancelClicked;
    }

    private void OnOkayClicked() { /* ... */ }
    private void OnCancelClicked() { /* ... */ }

    public void Dispose()
    {
        _view.OkayClicked -= OnOkayClicked;
        _view.CancelClicked -= OnCancelClicked;
    }
}

Now I don't know about you, but I dislike having to wire and unwire an event like this - there is too much chance that I will either forget to unwire one of the events, or when copying and pasting the Add code (I know, I know) to the Remove section, I will forget to change a + to a -.

To this end, I created a class that will auto wire events to handlers based on a convention. It was based off of the Presenter base class written by Mark Nijhof in his Fohjin.DDD sample application, with a few improvements (namely the unwiring of events). To avoid the need to make your Presenters inherit from a base class (and to not violate SRP!), it is wrapped up into its own class, which can be used like so:

public class EmployeesPresenter : IDisposable
{
    private readonly IEmployeeView _view;
    private readonly EventAutoWirer<IEmployeeView> _autoWire;

    public EmployeesPresenter(IEmployeesView view)
    {
        _view = view;
        _autoWire = new EventAutoWire<IEmployeeView>(view, this);
        _autoWire.Wire();
    }

    private void OnOkayClicked() { /* ... */ }
    private void OnCancelClicked() { /* ... */ }

    public void Dispose()
    {
        _autoWire.Unwire();
    }
}

The wirer supports conventions to allow easier hook-up - by default it will only hook events defined in the View's interface to private methods prefixed with "On" in the presenter. This means that any events which are only defined in the concrete implementation of the View are not wired automatically - allowing extra view only functionality such as when an item is MouseOver'd etc.

design, code, net

« Model View Presenters: Presenter to View Communication Model View Presenters: Composite Views »
comments powered by Disqus