The MVVM approach lends itself naturally to Silverlight applications. This is because the MVVM pattern is a specialization of the Presentation Model pattern that leverages some of the specific capabilities of Silverlight, such as data binding, commands, and behaviors. MVVM is similar to many other patterns that separate the responsibility for the appearance and layout of the UI from the responsibility for the presentation logic; for example, if you’re familiar with the Model-View-
Controller (MVC) pattern, you’ll find that MVVM has many similar concepts.
Note: Commands are not supported directly by Silverlight for the Windows Phone 7 platform, but by using behaviors, you can implement them in a friendly way.
Overview of MVVM
There are three core components in the MVVM pattern: the model, the view, and the view model. Figure 4 illustrates the relationships between these three components.
The view is responsible for defining the structure, layout, and appearance of what the user sees on the screen. Ideally, the view is defined purely with XAML, with no code-behind other than the standard call to the InitializeComponent method in the constructor, although as you’ve already seen, this is not always possible.
The model in MVVM is an implementation of the application’s domain model that can include a data model along with business and validation logic. Often, the model will include a data access layer. In the case of a Windows Phone 7 application, the data access layer could support retrieving and updating data by using a web service or local storage.
The view model acts as an intermediary between the view and the model, and is responsible for handling the view logic. The view model provides data in a form that the view can easily use. The view model retrieves data from the model and then makes that data available to the view, and may reformat the data in some way that makes it simpler for the view to handle. The view model also provides implementations of commands that a user of the application initiates in the view. For example, when a user clicks a button in the UI, that action can trigger a command in the view model. The view model may also be responsible for defining logical state changes that affect some aspect of the display in the view, such as an indication that some operation is pending.
In addition to understanding the responsibilities of the three components, it’s also important to understand how the components interact with each other. At the highest level, the view “knows about” the view model, and the view model “knows about” the model, but the model is unaware of the view model, and the view model is unaware of the view.
MVVM relies on the data binding capabilities in Silverlight to manage the link between the view and view model. The following are important features of an MVVM application that uses these data binding capabilities:
- The view can display richly formatted data to the user by binding to properties of the view model instance. If the view subscribes to events in the view model, the view model can also notify the view of any changes to its property values using these events.
- The view can initiate operations by using commands to invoke methods in the view model.
- If the view subscribes to events defined in the view model, the view model can notify the view of any validation errors using these events.
Note: Tailspin considered two other approaches for linking controls to code. The first was to use custom attached properties, but this meant that they would need to build an attached property for each control’s event that they wanted to bind to a command. The second was to invoke a method instead of a command from a binding, but this made it harder to handle the “can execute” type of information that commands neatly encapsulate. The “can execute” information is useful for enabling and disabling controls in the UI.
Typically, the view model interacts with the model by invoking methods in the model classes. The model may also need to be able to report errors back to the view model by using a standard set of events that the view model subscribes to (remember that the model is unaware of the view model). In some scenarios, the model may need to be able to report changes in the underlying data back to the view model; again, the model should do this using events.
Benefits of MVVM
The following are some of the benefits of clear separation of responsibilities in the MVVM pattern:
- During the development process, developers and designers can work more independently and concurrently on their components. The designers can concentrate on the view, and if they are using Expression Blend, they can easily generate sample data to work with, while the developers can work on the view model and model components.
- The developers can create unit tests for the view model and the model without using the view. The unit tests for the view model can exercise exactly the same functionality as used by the view.
- It is easy to redesign the UI of the application without touching the code because the view is implemented entirely in XAML. A new version of the view should work with the existing view model.
- If there is an existing implementation of the model that encapsulates existing business logic, it may be difficult or risky to change. In this scenario, the view model acts as an adapter for the model classes and enables you to avoid making any major changes to the model code.
Although the benefits of MVVM are clear for a complex application with a relatively long shelf life, the additional work needed to implement the MVVM pattern may not be worthwhile for simple applications or applications with shorter expected lifetimes.
You’ve seen a high-level description of the MVVM pattern, and the reasons that Tailspin decided to adopt it for their Windows Phone 7 client. The next sections describe the following implementation choices made by the developers at Tailspin when they implemented MVVM for the Surveys application:
- How Tailspin connects the view and the view model components
- Examples of how Tailspin tests components of the application
- How Tailspin implements commands, asynchronous operations, and notifications to the user
- Details of data binding and navigation
For more information about MVVM, see the Prism page on CodePlex (http://compositewpf.codeplex.com/).