For some reason the family of design patterns that exist around the Model View Controller pattern seem to be an elusive band of characters. The first time I encountered Model View Controller I studied the text hard trying to understand how the Strategy, Observer and Composite patterns worked together to accomplish some goal that – try as I might - remained fuzzy. Somehow I have a sense that I am not alone.
Model View Controller (MVC) is the parent pattern to a number of contemporary patterns that seem to find a natural home in Microsoft development. Variations of MVC have appeared over the years in an attempt to work within the construct of modern event-driven programming models. One of most distinguishing differences among MVC and some of the derivative patterns is that with MVC the controller executes first, where with the other patterns the view tends to execute first and then delegates control to some sort of “presentation” class.
A few years ago I did a series on Model View Presenter (MVP) [Design Patterns Bootcamp: Model View * Patterns] in an attempt to discuss how to completely abstract away the user interface layer. MVP proves to be an effective pattern, but can be confusing to some with the heavy use of interfaces and events.
The recent popularity of XAML applications has brought focus to the Model View ViewModel (MVVM) pattern, which is technically a fine-tuned version of Presentation Model that takes advantage of .NET’s data binding framework. Further, the advent of ASP.NET MVC has created a strong push for some sort of presentation strategy into the realm of ASP.NET WebForms.
So this history lesson is great, but how do you do you write the code to implement the patterns?
Introducing VM Workshop
The VM Workshop is a simple reference application demonstrating the Model View ViewModel and Presentation Model pattern in a number of different UI platforms.
The project includes examples in:
- ASP.NET MVC
…and as an open source project, you are invited to help add examples of how to deal with a myriad of different UI use cases!
The purpose of the VM Workshop is to be a working programmer’s reference, not an exposition in pattern purity. Therefore you may see small details that may not fit the textbook definition of the patterns, but the point is to provide a template for effective pattern use. For instance there is an example in ASP.NET MVC is included in VM Workshop. Obviously the pattern being implemented is Model View Controller, but the construction of a “view model” class is still relevant in this context. While referring to ViewModel class in a ASP.NET application may be technically inappropriate, I use the term “view model” to interchangeably refer to a ViewModel or Presentation Model class for simplicity.
I recently messaged John Gossman, arguably one of the most visible proponent of MVVM, to ask whether or not MVVM is exclusive to XMAL applications or if the pattern may be applied to any UI platform. John replied saying:
I think the pattern is completely applicable to any UI technology. There are some details around the use of commands and data-binding that tend to be XAML specific, so I tend to use MVVM for the XAML version of the pattern and to keep from having religious wars with Patterns zealots. The more general pattern is called PresentationModel by Fowler. OTOH, one of the nice things is if you design your Model and ViewModel’s correctly you should be able to reuse them between XAML-based and other UI technologies.
VM Workshop is meant to be a learn-by-example project showcasing different styles of implementation.
Examples in C# and VB.NET
Often discussions surrounding design patterns tend to only be available in C#. In order to extend the conversation to as many developers as possible, I’ve include a VB.NET solution that operates in complete parity to the C# version. The only difference in the VB.NET version is that due to lack of lambda support some of the places AutoMapper is leveraged in the C# version are removed and objects are mapped manually.
A Grid, a Form and an Action
The initial example is provided for all the UI platforms. Each implementation features the same UI and workflow composition. First a grid is presented to the user:
Upon selecting an individual item, an edit form becomes available allowing the user make changes to the item:
Note: These screen shots here are taken from the WebForms sample, but the UI reflects the appropriate look for each of the respective UI technologies.
Once changes are complete, and the ‘Save' button is pressed, the persistence operation is initiated. After persistence is complete, each implementation tells the UI to how to response respond to the action.
Please note that true persistence is not implemented in VM Workshop. In an effort to avoid using a database (which keeps the code more portable) persistence functions are simply stubbed out in the code. In the end, the project includes the same messages that would be sent among the application layers in any real-world application.
Minimizing Code in the View
The motivation for using these patterns is often creating a more testable user interface layer, decoupling your application from UI technologies or perhaps to promote better application composition. No matter what the motivation, the overarching goal is to remove application logic from the view layer. The examples in VM Workshop use a number of general concepts to achieve a thin view.
The grids are populated through a lazy loaded property on the view model class. This ensures that the request for data is restricted to only the times when the data wasn’t previously prepared. Another benefit is that a call to somehow ‘get stuff’ is not required. When the grid binds to the 'Products' property the property’s implementation knows where to get the data if it doesn’t have it.
Visibility properties (in XAML implementations) or boolean properties on the view model classes are used to control whether or not controls, messages or other UI elements appear to the user. Binding the state of these properties to the appropriate elements on the screen relieves the view of having to decide what is shown to the user and what is hidden.
No Logical Operations
While taking great care to remove all logical operations from the view, even seemingly benign tasks such as casting input into primitive types is delegated to the view model or some other class for execution. Even simple operations like type casting can quickly cascade into a series of business rules. Consider how convoluted validation scenarios can become when the application is expecting a currency value, but is one way or another served a string. While the validation does have UI implications, this type of logic is best handled in a lower level than the view.
Presentation Objects and Data Transfer Objects
The use of presentation objects or data transfer objects, or DTOs, (I tend to flip between terms depending on my mood) is used to accomplish at least two goals:
- Hide the domain model from the rest of the application. Concealing the full-fledged Products class from the view makes sure unnecessary pressure is not exerted on the model to mutate at the whim of the view.
- Make custom mapping the responsibility of the type. The presentation object’s job is to prepare the data coming from the domain model into a form that is natural to the view. This mapping or conversion responsibility is best placed in the hands of the presentation object and not within the procedure of an operation.
Check out the video that will get you oriented with VM Workshop:
The code for VM Workshop is available on CodePlex and you are encouraged to submit your implementations into the workshop!
Thanks to Infragistics for providing the time to develop the VM Workshop.