The ViewModel
The view model is a specific class responsible for synchronizing the state of a view. It is the mediator between the view and the model of the application. The view model queries the model for information and exposes the appropriate properties, collections, and methods to the view to enable data binding. The view model provides presentation separation, or a separation of how data is presented or input collected from the actual business logic that is applied to it.
The view model is specifically designed to take advantage of data binding and more often than not will implement the INotifyPropertyChanged interface. Most MVVM frameworks focus on providing a base view model implementation to provide services for data binding, property change notification, and commands that facilitate decoupling between UI events and methods which are called on the view model.
Figure 3 expands upon data binding to illustrate how it fits in to the MVVM pattern. Note that the two-way flow of information does not create a direct reference between the view and view model, but rather an indirect and decoupled path through the data binding.
Figure 3 Data binding with MVVM
The view model does not deal directly with control artifacts. For example, controls in Silverlight may have a visibility that determines whether or not the control is expanded or collapsed. Instead of referencing this directly, the view model synchronizes the context using a Boolean property that might be named IsVisible. In XAML, value converters allow the data binding to convert the Boolean to the correct enumeration that is expected by the control. During testing, it is easy to determine the state of visibility simply by querying the property on the view model. The runtime takes care of turning this into the XAML-specific implementation of the visibility property on the FrameworkElement.
The Importance of the View Model
Why is it important to have a view model? If your model is well-defined, you are able to provide unit tests and have the necessary decoupling and modularity to reuse components and wire the application using code-behind to bind items to the view. Patterns are meant to help solve problems and make it easier for developers to produce quality code. What problems does the view model solve?
There are three common problems that the view model solves. These problems will help you decide whether or not MVVM makes sense for your application.
Unit Testing of View State
While the model represents data, behavior, and services, a view has an implied contract of items that are necessary to make that view function. It is important that those functions behave in a consistent, repeatable, and testable manner, especially in large software projects that rely on automation to help reduce overhead and errors. It is very difficult to test an XAML-based view because it must be initialized and loaded onto a rendering surface, and then inspected to test for expected values and behaviors. Code that walks a visual tree is often fragile because if the structure is changed significantly[md]for example, what was once a list box is suddenly changed to a combo box that exists in a different column on the main grid[md]the code that expected that visual element will fail.
The view model adds an additional layer of separation that can be tested. In the view model, the data is organized into a list with a selected item. This is what is important for the end user: to browse a list and select an item. This organization of data and the act of selection can be tested independently of the view. Through data binding, the view can then be represented as a list box, a combo box, or even a data grid. While the visual elements may be different controls located on different areas of the screen, their data bindings are exactly the same and point to the list and the select item on the view model.
Reusability
Often the same set of data elements are represented multiple ways within an application. A list of product data may have a view that displays it as a grid, another view that shows a line chart, and a third view that represents the data using a pie chart. For all of these views, the underlying data is the same, and the requirements for interacting with the model to locate and process the data does not change.
The view model allows this data to be collected and presented in a single class that is reused by the different views (see Figure 4). The code is not duplicated and easily referenced in a single location, while the views are modified and styled independently. It is easy to add additional views that honor the same binding contract and reuse the same data.
Figure 4 View model with multiple views
MVVM allows for multiple views per view model. A single view, however, should only have one view model. A view that requires multiple view models implies a need to further decompose the view into smaller components which each connect to a single view model. If information is required from other view models in the application, a view model might connect to another view model for that information or participate in a messaging system to receive notifications about the data that is being shared.
Designer Workflow and “Blend-ability”
This feature is evident when working with larger projects with a separate design team. The traditional designer-developer workflow looks something like this:
- The designer mocks up a beautiful image of the target application and sends a screen shot as a static image to the developer.
- The developer hacks the image to pieces and pulls out his hair trying to duplicate the screen as best as possible using code and the dynamic pieces that drive the application.
- The designer pulls out her hair in frustration when the final application looks nothing like the comp provided in step 1, and spends hours trying to tweak the application to get it back in shape.
- The tweaking inevitably breaks some code that the developer must now come in to fix.
Using the view model as the “contract” for the data that will be represented in the view, it is possible to create a completely parallel workflow between the developer and the designer. As long as both teams agree on what items will be in a particular view, the developer can then begin building the model and view model to support those data elements. Using the agreed-upon contract, the designer can use what is known as a “design-time view model” or a simple container that holds sample data to build the screen. It doesn’t matter if they choose a blue theme or a red theme, use grids or list boxes and fire events with mouse-clicks or touch manipulations; all of this is translated to data bindings and commands that interact with the view model.
The workflow is no longer sequential. A team of dozens of designers can work on the design independently of the developers that can use unit tests to verify the view models and eventually wire the design and application logic together by swapping the design-time view models with the runtime “production” versions.
If you do not perform testing, are not concerned with reusability of code, and don’t have a separate design team with a parallel design process, MVVM may not be the right pattern for you to use.