So far in this series of articles, we have been taking topics that might be second nature to iOS developers and relating them to the relatively new feature set found in the Windows Phone 7 SDK. Typically this involves talking about a few classes and code samples as they might appear in iOS and then relating them to classes with a similar purpose in the WP7 SDK.
This article focuses more on a set of design patterns to illustrate that patterns themselves are universal and the code used to implement them is secondary to the pattern and its purpose. In this article we’ll take a look at the Model – View – Controller pattern and a variant of it, the Model-View-ViewModel pattern.
In a typical data-bound user interface you generally have a view composed of controls and these controls are usually bound to some underlying source of data. For example, if you have a customer edit form you might have controls like text fields for editing the customer’s name and address and other types of controls for editing additional customer data. The model in this scenario might be an object called Customer (which could be a regular Objective-C or C# object or it could have been served up by a database access library or an Object-Relational Mapper).
If this were an iOS application you might have created a class called CustomerEditViewController which inherits from UIViewController. The view is actually a view hierarchy composed of controls that allow a user to edit customers. Because iOS doesn’t actually support bindings the way the full desktop version of Cocoa does (or WP7 for that matter) the controller has to do an awful lot of work to react to user input and manually force values into control properties.
A typical Model-View-Controller interaction looks like the following diagram:
In a bindings-capable environment, the model is bound to the view and the model is loaded and updated by the controller. Additional properties of the view are dealt with by the controller and user interaction events are passed on to the controller for handling.
This works out pretty well in many scenarios and it’s original goal of separating concerns to make our applications easier to maintain and debug is still valid. Unfortunately what happens quite often is that with the MVC pattern we only have a single model. In order to keep bindings working, we end up making changes to the model to accommodate things that only have relevance in the UI. For example, we might add an isSelected property to the Customer class so that we can modify the background color of currently selected customers or, we’ll add a CurrentCustomer object to some other model and use that to help our UI maintain navigational consistency.
In a typical iOS scenario, we might have a UITableViewController subclass. This class is responsible for handing instances of custom view cells to the UI subsystem. It performs the customization of these cells by pulling information from a model.
What we really need are two different types of models. The first type is a model that represents the actual source of data which will more than likely be some kind of POCO (Plain-Old C# Object) that came from a database, an XML file, a Web Service, or somewhere else. The second type of model is a model whose properties and behaviors are designed specifically to support the view with which the user interacts. This type we call a View Model, and it is part of a variant of the MVC pattern called Model-View-ViewModel.
In a Model-View-ViewModel pattern, we take advantage of the fact that virtually all aspects of our user interface can be controlled via data binding. We wouldn’t really need to add the complexity of this pattern to our iOS applications because we don’t have bindings support but it comes in extremely handy when building large Windows Phone 7 applications.
Notice that this pattern doesn’t actually have a controller – there is no single over-arching all-powerful class that is responsible for coordinating everything. This takes a little getting used to at first, but, once you’ve gotten into the habit of building highly data-bound UIs in Windows Phone 7, the use of MVVM seems like a natural evolution.
As mentioned, MVVM is a pattern, it is a way of doing things and, as such, there is no single right way of doing it. For example, one thing people strive for in MVVM is to have as little code in a view’s code-behind as possible (it’s really not possible to avoid this entirely). If you ask folks building MVVM applications today about code-behind, you will probably start an argument.
One concept that is especially hard for iOS developers to let go of is the idea of the controller. If you find yourself writing code that looks like this:
myControl.Text = myModel.Property;
Then you need to stop right there – this isn’t MVVM. Your view needs to be bound to a view model and the properties of the various controls and sub-controls should all be set via bindings and converters wherever possible. The trick with MVVM is figuring out how your view needs to get instances of view models. You can do this by creating factory methods, or you can use a view model locator, which is a static helper class responsible for doling out instances of view models to views.
Take a look at the following XAML, which illustrates how you might create a single customer view that is bound to a view model object:
1: <phone:PhoneApplicationPage x:Class="MyApp.CustomerPage"
2: ...
3: DataContext="{Binding Customer,Source={StaticResource Locator}}">
4: ...
5: </phone:PhoneApplicationPage>
Basically what we’re saying is that there is a view model object called Customer to which this entire page is bound. This is also a very common practice with MVVM – try and make the binding as wide in scope as possible. It might be hard at first, but try and match your view models directly to pages and user controls. The benefit of having a view model in addition to a data-centric model is that you can have multiple view models for a single model, with each view model tailored specifically for a given control or page.
Inside our App.xaml we can declare a global resource that points to the view model locator:
1: <Application.Resources>
2: <vm:ViewModelLocator x:Key="Locator" />
3: </Application.Resources>
Here “vm” is the namespace prefix of the CLR namespace where we have our view model locator defined. This class really just has public properties on it that allow our XAML to obtain instances of view models. This is also unfamiliar territory for iOS developers and developers who traditionally follow a more MVC style. Instead of having a controller object that knows about the view and knows about the model that is responsible for hooking the two up, the view declares its intent via bindings. In the sample case, the view says that it should be bound to a view model called Customer which can be found on the view model locator class. The view model locator is responsible for instantiating the view model. During this instantiation, the view model also typically has an initialization method which is called directly or indirectly (again, this is a source of difference and debate depending on how you decide to implement your MVVM pattern).
So the flow of control and instantiation might go something like this: Customer View Page –> Locator –> Customer View Model –> Customer Model (database or web service source).
The UI intentionally has absolutely no idea how the bound data is actually persisted on disk (or in the cloud). All it cares about is how the data is represented visually to the user and made available for interaction – this is the job of the view model. Many of the tasks we traditionally keep in controllers, such as responding to user input and manipulating model values, all take place within the view model whenever possible.
At first you might be thinking that MVVM seems a lot more complicated than just having code-behind in your WP7 views that manipulates controls directly, especially when this looks a lot like the code you may have been writing in iOS. For really small applications, this may be true. However, once you start writing applications that have several pages and these pages have multiple controls, different states, and need to respond to when users navigate to and away from those pages and finally when you try and attach an asynchronous data source (such as web services in the cloud) to your application – the small increase in complexity of code is well worth it in the long run.
Bindings is only a small part of MVVM, it is far more than that. Let’s take another very common scenario – navigating between pages. In iOS, you might write code in a method that is invoked when a user selects a row in a table view. Here, you might create an instance of the view controller responsible for the next screen and then pop it into the stack via the navigation controller. If this view controller needs a model in order to prep the UI, the parent controller is often responsible for creating an instance of this model, loading it from some source, and then passing it as a parameter to the child controller.
With MVVM we do things a little differently. A user might tap a button which results in the execution of a Command object that is actually a property of the view model (view models encapsulate both behavior and data!). As a result of this execution, a message might be broadcast indicating that Customer 123 has been selected. The CustomerViewModel class is listening for such a message. When it receives this message, it loads Customer 123 from disk, populates all of its properties accordingly, and then tells the WP7 navigation system to navigate to the CustomerView.xaml page. As you can see, the “concerns” here are even more separate than in MVC – the parent controller doesn’t actually know what happens when someone selects a customer and many proponents of MVVM argue that it shouldn’t. The view model that backs the view that should appear upon selecting a customer is responsible for listening for the event (or events, and this is key to re-usability) that trigger the appearance of that view.
It might seem like a minor detail but if you go back into an application written MVC style a few months after writing it – it could take you a very long time to figure out all of the different paths through an application. If you’re looking at an MVVM view model, then a quick glance at the message subscribers on that model will tell you exactly the list of actions that can cause that view to appear.
In this article I’ve tried to explain the basics of the MVVM pattern and how it differs from the MVC pattern that iOS developers are familiar with. I have deliberately avoided talking about any one MVVM implementation because the decision as to which MVVM library you use (or whether you roll your own) is entirely up to you.
MVVM isn’t limited to just Windows Phone 7, and there are implementations on just about every platform you can imagine. For Windows Phone 7, the library that I have used most often is MVVM Lite. If you don’t feel like writing your own view model locator classes, your own pub/sub messaging system, and your own command helpers, then using a library like MVVM Lite will save you a lot of time and effort.
At one point, the installation process for MVVM Lite was so cumbersome that many people just wrote their own stuff rather than attempting the install. Recently, they have released an automated installer that makes adopting MVVM Lite much easier. You can find the code for MVVM Lite, the downloader, and related documentation here: http://mvvmlight.codeplex.com/.
In closing, iOS developers are very used to having to manually fetch objects from a data source via a controller and then, using that same controller, instantiate custom views and set view properties and manually build view hierarchies programmatically. Using the MVVM pattern on Windows Phone 7 allows developers to take full advantage of bindings, resource dictionaries, templating, and the flexibility of Xaml-based object hierarchies. As an iOS developer if you ever find yourself writing code like this:
myControl.Text = myModel.TextProperty;
Then you should take a step back and see if the MVVM pattern and possibly an MVVM toolkit might help you.