Search code examples
.netwinformsmvppresentation-model

Am I implementing the MVP / Presentation Model UI pattern correctly?


I'm re-working a Winforms application and would like to employ a variation of the Presentation Model pattern for the UI. Could someone tell me from the following explanations if I'm doing it correctly?


I have decided to set up dependencies as follows:

   Model <---- Presentation Model <---- View

That is:

  • The model is not aware of anything except itself.

  • The presentation model has a reference to the model (but not vice versa).

  • The view has a reference to the presentation model (but not vice versa).

I am using Winforms data binding to keep the view and the presentation model synchronised.

Now this all works like a charm, except when I need to deal with e.g. a click on a form's "Close" button. Since the presentation model has no reference to the view, it cannot subscribe to any events published by the view. Thus I've come up with the following crutch:

Presentation Model                   View
+--+                                 +--+
|  |                                 |  |
|  |                                 | <--------X closeButton.Click event fires
|  |                                 |  |
|  |                         +--------X |
|  |   CloseRequested = true |       |  | 
|  |                         +--------> |
|  |                                 |  |
|  | CloseRequested   CloseRequested |  |
| <-----------------------------------< |
|  |                                 |  |
| X--------+                         |  |
|  |       | IsClosed = true         |  |
| <--------+                         |  |
|  |                                 |  |
|  | IsClosed              MustClose |  |
| >-----------------------------------> |
|  |                                 |  |
|  |                                 | X--------> view.Close()
|  |                                 |  |
+--+                                 +--+

That is:

  • The user clicks the "Close" button.

  • The button's Click event is captured in the view, which reacts by setting the property CloseRequested.

  • Data binding transfers this value to a corresponding property in the presentation model.

  • The presentation model reacts to this change by setting its property IsClosed.

  • Data binding transfers this value into the view's MustClose.

  • The view reacts to this change by closing itself.

The presentation model is quite nicely decoupled from the view, and vice versa, however this is a lot of work only to process a single button command. Is there an easier way, given the dependency graph I've decided on?


Solution

  • I've recently been converting a Windows Forms application to the MVP architecture, and it looks like you've set up your dependencies in a similar way to what I've been doing. However, I simply have an IPresenter interface which defines methods to allow the view to pass on user requests. As the view already has a dependency on the presenter and a reference to it, it seems sensible to simply call request methods on it directly.

    So in my system, the presenter listens to events from the model and fires its own presentation events for any interested view to listen out for. The view responds to those events by updating itself as appropriate, and forwards user requests to the presenter when they are made.