Comprehensive, Practical Guide to Model-View-Presenter in C# Winforms

This article is a work in progress!

If you have been given this url, I hope you can provide some early feedback for an article that is work in progress. I may also link to an incomplete page (to help me not forget), so apologies if you've arrived here by accident.

This draft was published: November 11, 2015

Check back soon for the complete article!

Several months ago, having scoured search engines for several hours for guides, examples, repositories, and general information relating to the Model-View-Presenter (MVP) pattern, applicable specifically to .Net Windows Forms Applications (WinForms), I came up short. The company I had just taken a role with used WinForms extensively, and any roadmap for moving the company to much more familiar Web and Cloud technologies was going to be a long road. Sans resource material, I soldiered on from mud, through blood to the green fields beyond, placing me in the seemingly unique position of being able to provide advice and practical information for those wishing to achieve the same.

It seems prudent to, at an early stage in this article, provide the list of requirements to which I was determined to fulfill. If you are not interested in similar requirements, I you may find the remainder of this article of much less use. I will also mention that several assumptions are made throughout the article as to the skill level of the reader (that’s you). I will try to provide links to related resources throughout, but please use the comments section at the bottom of the page for any specific questions.

Tests

Although business requirements and their respective user stories ultimately drove my work on (what I will affectionately refer to as) the legacy code base, there were some key aspects and infrastructure I needed in order to complete my objectives in a professional manner.

Specs

The list of technical requirements, as will be explained, are much more a chain of requirements. The first link of that chain, and I would hope of any development work, are the user stories. The first step from a development point of view however, or the second link in aforementioned chain, were the tests. My team and I were able to translate the user stories into specs, or more specifically, a feature file in specflow.

This is a great practice that the whole team should be involved in, as you will very quickly flesh out both the design and the requirements, making sure you do in fact have all the information you need before starting development; a great practice to prevent starting on some work and then having to shelve it whilst further information is sought.

I don’t want to bog this article down with usage info regarding SpecFlow because, for many, this may be an unnecessary first step. We simply use these specs to drive the rest of our work, usually developing with one failing spec driving the current development. By describing the user interactions through familiar Given/When/Then syntax, you start to get a feel for the UI components that will be necessary, and a feel for the UX. You may of course flip this on it’s head and create a mock UI or wireframe for your end users to sign off, which would then lead to the creation of your specs. Whichever works for you.

Unit Tests

With a failing end-to-end test in place, we can start with our unit testing. Again, I’m not going to go into uniting testing each layer in a typical n-tier system; I only want to look at the UI in this article. The first test I go for is that my application is actually going to be able to load my view (whereby the view is my Form). Now I suspect this will sound odd to some, why on earth wouldn’tmy application be able to load the form? Simply because my form will almost always be required to fetch something from my persistence layer, and/or process some logic in my domain. In order to achieve that, and conform with the Dependency Inversion Principle, I opt to use Dependency Injection.

By always having a test that checks the anticipated composition graph of the respective host is valid for my view, I protect myself against changes to composition. I appreciate there’s a couple long words there, so time to show some examples.

Windows Forms Composition Example

The following example uses the Compose package, which we’ve extended as follows for WinForms compatibility (note, we intend to push this change back up to the repository so with a little luck you won’t need to do this):

public class WindowsFormsApplication<Form> : Executable where Form : System.Windows.Forms.Form
{
  public WindowsFormsApplication()
  {
    this.OnExecute<Form>(form => Windows.Forms.Application.Run(form));
  }

  protected override void PreServiceConfiguration(IServiceCollection services)
	{
		services.TryAddTransient<Form, Form>();
	}
}

There’s quite a lot going on in the above snippet so I’ll walk through it briefly. Compose provides these Execution classes that can be extended to inherit all the fancy composition features such as dependency injection. By having WindowsFormsApplication inherit from Execution, we get access to everything Compose has to offer.

In the constructor, we set up our execution; the action that will be run when we execture our application. Hopefully the content of the lambda is familiar to you because it’s essentially the same code that is included in new Windows Forms Application templates. The difference, and perhaps a source of confusion, is the generic. Simply, if you specify a generic on the OnExecute method, the Compose library will use your composition graph to dependency inject the specified service.

The final detail of note in the snippet is the TryAddTransient call in the PreServiceConfiguration method override. Here I’m utilising Microsoft’s Dependency Injection library to create a self binding for the form. Whilst some DI containers assume a self binding for unregistered types, Microsoft’s container requires explicit bindings.

Written on November 11, 2015