28 Apr Windows app design with MVVM
The MVVM pattern
The Model-View-View Model pattern was developed at Microsoft to target platforms supporting data binding. Originally based on the popular Model-View-Controller (MVC) pattern, MVVM has become very popular in WPF, Silverlight and Windows Store Applications in addition to also being supported in HTML5, Java and other platforms.
The pattern is based on the principle of separation of concerns, dividing code into three parts that interact in a consistent predictable way.
The model represents data; examples include a flight, an airport, or a route. The model should also include any business rules related to the data.
The view is the graphical representation of the model expressed in XAML. For example, if your model is a flight the view for that model could be a simple grid showing the flight number, departure time and arrival time or something more complex such as a map showing the path of the flight. The view is also receiving the user inputs.
The view model acts as the mediator between the view and the view model. This alleviates the need for models to know how their data is going to be displayed, which allows them to be loosely coupled. The view model will contain references to one or more instances of one or more models and will interact with these models directly via their properties, methods and events. Interactions with the view are mainly done via data bindings. These bindings allow for two way communication between the view and the view model to update values on the view from the model. This should be the only method through which views and view models interact. There should never be a direct reference to a view in a view model.
MVVM Light (http://www.mvvmlight.com/)
MVVM Light is a lightweight and easy to learn framework exposing common functionality for MVVM applications. It includes base class implementations of bindable and ViewModel objects. In addition it supports a messaging system for communication across loosely coupled elements. MVVM light also includes a simple dependency injection implementation to help further decouple an application. Commanding is also supported via RelayCommands. MVVM light is usable across many platforms including Universal Apps.
The Prism framework is a feature rich platform to help solve common issues with MVVM applications. It includes base classes for bindable and ViewModel objects in addition to base classes for navigable views. It supports a publisher-subscriber pattern for messaging through its EventAggregator. Prism does not contain a dependency injection system outright, but it does have extensive hooks and integration with the Unity library also from the Microsoft Patterns and Practices group. Prism also provides solutions to other common MVVM issues such as ViewModel navigation, state saving, model validation, suspend and resume and commanding. Prism was initially implemented for WPF and Silverlight and since has been ported and simplified for use in Windows applications. For more information, visit the .NET blog.
.NET events raised through the standard .NET eventing paradigm create strong references which, if not unsubscribed when an object is disposed, can cause objects to not be garbage collected. This kind of a framework makes it easy for developers to write code that can lead to memory leaks and other difficult to diagnose issues. One solution is to use an “off-the-shelf” solution. Descriptions of two of them are below.
MVVM Light’s Messenger
The Messenger is a lightweight implementation of the Publisher-Subscriber pattern that allows for the passing of messages across view models. It also integration into the MVVM light base classes enabling notifications of property changes across view models.
The EventAggregator is a popular and well used implementation of the Publisher-Subscriber pattern that is commonly used in large scale enterprise applications. It supports having weak references (delegates) to events allowing subscribers to be disposed of even without explicitly unsubscribing from an event. Other features include the ability to request that events be returned on a particular thread (background or UI) and filtering out of unwanted events via a predicate.
In some cases, ViewModels are instantiated by their associated view, are static instances, or are created and exposed by the application ViewModel. All of these options tightly couple the ViewModel to its creator (the view, the single instance, or the application ViewModel). This can make testing especially difficult.
For instance, here is the method LoadListAsync() in an example class.
If a unit test were required to test some functionality inside of LoadListAsync, an instance of the ApplicationViewModel would have to be created, in addition to an instance of the UpdatesViewModel (the value returned from the ApplicationViewModel.Default.Updates property). This tight coupling makes refactoring very difficult. If ApplicationViewModel were to change or lose its reference to the UpdatesViewModel all the associated references would also have to change. A better approach would be to inject the dependency of the UpdatesViewModel directly into the example class. Here is an example in the MVVM Light framework.
MVVM Light SimpleIOC
The SimpleIOC container in MVVM light makes registering a dependency simple and straightforward. A ViewModelLocator class would be created registering each dependency, shown here.
Once the dependencies have been registered with the container (here the container is the SimpleIOC) they can be injected into the constructor of objects that need them.
You can see now the example class doesn’t even need to know about the ApplicationViewModel. All it cares about is the UpdatesViewModel which is dynamically injected via the SimpleIoc into the constructor. This now more loosely couples example class to the UpdatesViewModel. An even better approach would be to pass an interface in rather than a concrete instance, something that is also supported by the SimpleIOC.
Design Time Support
Support in designers is a hugely beneficial feature that can save developers many valuable cycles when implementing new functionality. Therefore supporting the Visual Studio designer with valid and useful design-time ViewModels should be seen as a cost saving feature of design-driven development.
Note: Some parts of an application will be unable to support design-time development. DirectX controls do not support rendering at design-time.
Implementing design-time support is easy and consistent across frameworks. You just need to add a design time instance to the view declaration. This instance is simply a reference to a folder called DesignViewModels that contains design-time view models with sample data. The sample data can make basic web service calls but should not perform any file operations. Having multiple Design-Time view models for the same view can help as well. Creating different ViewModels that exemplify different conditions or states of the view model can allow developers to see how a particular view reacts without needing to run the application. Switching between these different models just requires changing the value in the view declaration.
For a more detailed look into design-time development including ways to excluding design-time ViewModels from builds, please refer to Laurent Bugnion’s article.