I’m not going to get into what MVC is or the benefits of it, I wanted to talk about implementing it in Winforms. MVC is a first class citizen in the web development world, where all the cool kids are, but back in the dithering, slowly moving and, I suspect, mostly legacy Winform world it hardly gets a look in. I have worked with it before but with the emphasis on the controller, the view and model were very tightly coupled to the point it could have been called CVM. I’ve recently embarked on a small Winform project in my spare time and decided to revisit implementing it inside of that.
The project is a GUI version of the command line tool MKLink to create symbolic directory links, it’s been quite a feat in over engineering while I feel my way through abstracting standard BCL calls for unit testing (more on this in another post). I started by defining the model, I don’t have a traditional model in the form of some data I want to operate on but I do have the algorithm to copy any existing folders to a temporary location, delete the folder, create the link and copy the folder back, so this is the model. One point I’d like to make to here is about unit testing, I created an interface to abstract out some Path and Directory based .Net framework functions then another that my controller will work against (the model) to get work done. It feels like I have an unnecessary level of abstraction because of the two interfaces that do more or less the same thing.
A is the abstracted BCL calls and B is the actually worker class, for the most part IDirLinker just calls IDirectoryManager like so:
The view is much easier to define as it is the WinForm but I need a way to push data to it in a strongly typed way. To do this I created a interface with fields to represent the data I wanted to display, the end result for the main view was:
You may notice ther are two events on this interface, one problem I had to overcome was button and action related events on the main form. I want to put as little code as possible in the view, to enable this I added events to the view that the controller can register with. I can then wire up the OK button press to the PerformOperation delegate and have the minimal code in the view. Validation is a different matter, Winform validation is something I dislike intensely and have had many a problem with it. The logic to validate data is definitely logic I want to keep in my controller and be unit testable but the displaying of errors should be handled by the view and, arguably, the decision as to when data is validated. On the view I used an error provider to show the fields in error but I couldn’t avoid adding logic to call the ValidatPath event when the OK button is pressed or when the editor value changes. A better way of doing this maybe to tag the public field with an attribute that takes a validation type and the control that displays the data, so you would end up with something like [ValidateData(ValidateType = FolderPath, Control=txtFolderPath)], this needs developing further but I can see a problem straight away of needing a common base type for all Control types. I don’t think this is possible since Telerik, Devexpress and Winform controls all seem to have different bases.
The implementation of this interface falls to my old friend DataBindings. The view implements the interface and simply binds to the public fields like this:
Finally the controller pulls all this together in a nice unit testable way. Not a lot special going on in here, it simply shows the view and asks the model to do the work when everything is valid. The current interface looks like this:
It’s using poor mans DI to get the required implementations in and has a start method to return the view. When the Start method is called it setups any default data, registers the event handlers we created on the view and returns a reference to the view. The reference to the view is used by Application.Run() to start the main application loop. Since this is the main controller it makes sense to have this here. Program.cs simply creates all the required classes and starts the app with the IMainController’s form, like so:
This is the MVC model I will use going forward at work, it requires a few tweaks but I think hope it will scale well in larger projects. I’ve looked around the internet and can’t see much written on the subject, if you have a link to share I would love to see it.
PS watch this blog for the release of this app (along with its source) and an update to it to use AutoFac.