The Model-View-Control (MVC) pattern is more popular than ever. Microsoft has now jumped the bandwagon with its ASP.NET MVC framework. Other popular frameworks like Ruby on Rails, Django (Python) and the Spring MVC Framework (Java) all implement this popular pattern. The MVC pattern fits nicely into the request-response based nature of the web. As a request comes in, the controller makes a decision on what needs to be done, talks to the model and hands of the rendering responsibility to a view engine.
Silverlight on the other hand, even if it is running inside the, has more in common with rich client application frameworks like Windows Presentation Foundation than traditional web applications. This requires different thinking when it comes to architecting the application. In this post I’m going to talk about the View-Model-ViewModel (MVVM) pattern or as Fowler call it; the Presentation Model. As an example I’m going to re-factor my YouCard application to use this pattern.
Jon Gossman and Dan Crevier have blogged about the MVVM pattern in a WPF context, and recently Nikhil Kothari wrote an excellent post titled "ViewModel Pattern in Silverlight using Behaviors". Martin Fowler has also written about this pattern, but under a different name; the Presentation Model. What makes ViewModel so interesting for Silverlight and WPF applications is that it lets you take full advantage of the strong data binding support in Silverlight and WPF. One of the key concepts of the MVVM-pattern is to define specialized models that are tailored for a specific view (user interface). The view-model may contain special fields like IsDiscountingEnabled, or PageTitle that may be based on one or more fields form your under laying domain model. Your IsDiscountEnabled field might be based on whether or not the logged on user belongs to a specific group that have the permission to give discounts, but the actual view does not know or care about this. The view only cares about the IsDiscountEnabled field of the view-model, and is not coupled to the domain model. The view and the view-model are highly synchronized, while synchronization between the view model and the domain model only happen at certain points, like when the user hits the Apply or Save button. How you implement this synchronization between your view and your view model depends on the technology you use, but even Fowler suggests that this can be done through data binding:
Probably the most annoying part of Presentation Model is the synchronization between Presentation Model and view. It's simple code to write, but I always like to minimize this kind of boring repetitive code. Ideally some kind of framework could handle this, which I'm hoping will happen someday with technologies like .NET's data binding. – Martin Fowler
The synchronization code Fowler is talking about is the code where you move values from the name-textbox to the name-property on your Person object. I’m sure we’ve all written that code and can agree that it’s both boring and repetitive! Thankfully data binding has improved a lot since the .NET 1.1 and Windows Forms days, and in WPF and Silverlight data binding is a natural choice for implementing this synchronization.
The application I’m going to use as an example of this pattern is my YouCard application from REMIX Australia. At REMIX I talked about Silverlight 2 for designers. The focus of the talk was about using Blend 2.5 to build and design applications. The core of the application is a YouCard user control, which is data bound to a YouCardData class. This class contains functionality to retrieve data from Twitter and Flickr, and acts both as the model and the view-model for the application. It contains View-specific fields like Tweet, Name and Bio, which all are extracted from the Twitter-feed downloaded from Twitter using HTTP requests. The YouCardData class starts a timer that downloads new data from the Twitter or Flickr at given intervals. To follow good programming principles like single responsibility, I’m going to split the Twitter and Flickr functionality out to external classes. These classes will be our Model. The responsibility of these classes will be to download and parse XML into objects. The YouCardData class will become our ViewModel and will be responsible for using the Twitter and Flickr service in a way that makes sense for the View, and surface up any fields needed by the UI. Since the original design of the YouCardData class was built to highlight the strong support for data binding- and design time support in Blend 2.5, we have a good starting point for this refactoring job. The following diagram shows the current design (left) and the desired design after some refactoring:
The first thing that needs to be done is to define some interfaces for the external services. Instead of defining an ITwitter or an IFlickr interface I have decided to use more generic names like IMicroBlog and IPhotoService. That makes more sense if we ever want to support FriendFeed, Picasa or perhaps Windows Live Photo Gallery. I am going to refactor the existing code into two concrete implementations of each interface, one for the real online service, and one mock implementation with dummy data. As I mentioned earlier this application was written as a demo for the creative track at REMIX, and to provide a good design-time experience in Blend we need to generate dummy data when the code is being consumed by the designer. If you are going to benefit from the designer-developer workflow XAML enables, you need to start thinking about how your code behaves inside the design tool. In the current implementation dummy data is provided in the YouCardData class through an if-statement in the constructor checking if we’re running inside Blend or not. If we’re running inside Blend the YouCardData class will use a mock implementation of the Twitter and Flickr services. If it’s running inside the browser it will start a timer and begin to download data from Twitter and Flickr using the real implementations. The important part of the YouCardData constructor now looks something like this:
You might notice that this code screams for some dependency injection, and that is exactly what I’m going to cover in my next blog post. We check the type of the current application object. Blend provides its own application object, while actually running the application gives us our own application object.
The next piece of the application that needs some refactoring is the main user interface. By that I mean everything around the cards. Today the application contains one text box where you enter in a Twitter-username, and an add-button to add a new card. In the click-event handler we instantiate a new YouCard user control and add it to a stack panel. We also hook up an event handler listening for a close-event fired by the YouCard control. If the event fires we remove it from the stack panel. This approach is bad for a number of reasons. The main problem is that we are building too much behavior and logic into the view (the code behind of the XAML page). For instance the designer doesn’t have the freedom to change from a stack panel to a flow panel without changing the code. It’s also hard to unit test the code since much of the application logic is bound to specific UI-controls and UI-events.
To solve this problem we create a new view-model that contains an observable collection of YouCardData objects called Users. This collection is bound to an items presenter control, which uses the YouCard user control as its data template.
With both pieces of UI bound to view-models we have now control over how we display data. But this is just half the story of an application. We also need a way to interact with the view-model as the user adds or removes cards.
In the YouCard application there are two points of interaction that affects the view-models, the textbox and button to add a new user, and the red button to remove a card from the list. The user can type in a username and hit enter, or click the add button to add a new item to the Users collection. The add button should only be enabled if the user name is valid. When the user clicks the close button of a card we need to remove the item from the collection in the view-model. In this case it involves communicating from one view to the view-model of a different view. The YouCard user control needs to tell the view-model for the main UI to remove itself from the list.
The most obvious solution could be to add a click event listener on the add button, and call methods on the view-model to add a new users. We could listen to the text changed event of the textbox to validate the input and enable/disable the textbox based on the text. We could also add an event to the YouCard control that gets fired when the user clicks the red button. The main view could listen to this event, and remove the corresponding card from its view-model. The problem with this solution is again that we will be baking logic and behavior into the views, which should be owned by the designer. It also makes it harder to unit test things like the validation rules, and that any users added or removed is persisted to the local machine using isolated storage (the application stores the list of cards you have added).
To solve the interaction between the view and view-model we’re going to apply the command pattern. The command pattern enables us to encapsulate an action into a command object. The command object normally contains an execute method, a name and description, and some information about whether or not the command is enabled. A single command can be attached to multiple UI elements. You might want to invoke the open-file-command from a button, a keyboard shortcut and a menu item. WPF have built-in support for Commands, but this is not included in Silverlight 2.
Nikhil introduces some really cool ideas on how to enable command-like functionality through Silverlight behaviors. This is the same concept used to extend ASP.NET controls with AJAX behaviors. In his first ViewModel post Nikhil uses the following syntax to invoke commands from XAML:
Using an attached property he adds a behavior to the button which invokes the Search-method on the view-model, passing in the text property of the search textbox as the parameter. In a follow-up post Nikhil shows how he managed to get the syntax even more compact using the Dynamic Language Runtime:
The cool thing about this approach is that you can write any dynamic language expression into the attached click event. This can include method invocations and getting parameters from other elements on the page. This gives you amazing flexibility to link your view to your view-model. The problem with this approach is that you get a dependency to the dynamic language runtime, which will affect the size of your Silverlight application. But more importantly for me it breaks design time support in Blend 2.5, so we need to find an alternative approach.
I decided to use a more classic command pattern implementation found in the "Silverlight Extensions" project on CodePlex. The project contains controls, helper classes, extension methods and more. Since we’re only interested in the command pattern implementation I decided to move those classes into the YouCard project. The XAML for our textbox and button now looks like this:
The textbox is bound to a Username-property on the view-model. Both controls invoke the AddCard-command, using the username of the view-model as the command parameter.
The commands are defined like this:
The static Commands-class holds a reference to all the commands available in the application. When instantiating a new Command-object it gets added to a static dictionary on the Command-object, caching any command object created by the application. When using the CommandService-attribute from XAML, the CommandService class will link the UI-element with the correct command using a CommandSubscription class. When the user clicks the Add User-button, or hit enter in the textbox, the CommandSubscription-class will listen for the correct UI-event and trigger the Executed-event for the correct Command-object. Any class that wants to take action when this command executes simply listens to the Executed-event of the Command object. In our case we want to handle adding or removing cards in the view-model class:
Also worth mentioning is the enabling/disabling of the Add User-button. This is done through data binding the IsEnabled-property of the button to an IsAddEnabled-property of the view-model. The IsAddEnabled-property looks like this:
The textbox is bound to the Username-property, which will trigger the PropertyChanged-event for the IsAddEnabled-property. In the getter of the property we apply the validation rules that decide whether or not the button should be enabled.
Hopefully this post gives you another example of how the Model-View-ViewModel can help you keep as much code as possible out of your user interface. The strong data binding support in WPF and Silverlight makes this pattern particularly interesting, as you don’t have to worry about synchronizing your view and your view-model through hand written code. Using commands you can separate the actions of your application from the concrete UI-element invoking it. This gives your designers the freedom to choose which UI elements to use to invoke different actions in your application. Best of all, we’ve been able to do all this without breaking design-time support in Blend. In my next post we’ll continue on improving the YouCard application making it more testable by introducing dependency injection.