2012
Volume 27
MVVM - Using the MVVM Pattern in Windows 8
By Laurent Bugnion | 2012
Any programmer with previous experience in any of the XAML-based frameworks has probably at least heard of the Model-View-ViewModel (MVVM) pattern. Some have been using it extensively in all of their Windows Presentation Foundation (WPF), Silverlight or Windows Phone applications. Others have avoided it, either because they misunderstand what the pattern does, exactly, or because they don’t want to add what they see as a new level of complexity to their application.
You don’t have to use the MVVM pattern to build XAML-based applications. It’s absolutely possible to use traditional patterns such as event-based interactions to create compelling apps. However, decoupled patterns such as MVVM bring quite a few advantages. Notably, the MVVM pattern can tremendously enhance the experience in Expression Blend and facilitate the designer-developer workflow.
Recently—and especially with the extension of XAML to new platforms such as Windows Phone and, of course, Windows 8—the usage of MVVM has grown to a whole new level, from a niche pattern that only a few enthusiast coders were using, to a mainstream practice encouraged by Microsoft.
Preconditions
This article demonstrates how to use the MVVM pattern together with the MVVM Light Toolkit, an open source toolkit that facilitates common operations in XAML-based applications. To follow through the examples, Visual Studio 2012 is needed, as well as the latest version of the MVVM Light Toolkit. Note that you can use the Express edition of Visual Studio 2012, which is available for free. Of course, any other edition can also be used.
Visual Studio 2012 can be downloaded from bit.ly/vs12rc(Ultimate, Premium or Professional editions). The free Express edition can be downloaded from bit.ly/vs12express.
The MVVM Light Toolkit installer can be downloaded from the Download section at mvvmlight.codeplex.com. After installing the MSI, a Readme page opens and you can choose to install project and item templates for the version of Visual Studio you’re using.
The MVVM Pattern in Windows 8
Windows 8 relies on a new set of APIs named the Windows Runtime (WinRT). There are three possible ways (sometimes called “projections”) to program applications running on the Windows Runtime.
The first way is probably the most intuitive for people with skills in other XAML-based frameworks such as WPF, Silverlight or Windows Phone. It uses XAML as a front end, and C# or Visual Basic for its logic. While there are a few differences between Silverlight and the WinRT XAML/C#/Visual Basic projection, the skills and most concepts are the same. In fact, MVVM is the pattern of choice for this projection, for the same reasons as in those older frameworks.
Second, developers familiar with HTML and JavaScript can also code Windows Store apps with an HTML-based projection. With the growing popularity of MVVM in XAML, HTML developers have wanted to use data binding in HTML/JavaScript too. Because of the lack of data-binding mechanisms, however, it was necessary to start from scratch and to recreate this functionality. This is what frameworks such as knockout.js (knockoutjs.com) are doing. Such MVVM frameworks can also be used for developing Windows Store apps.
It’s also possible to use a proprietary framework from Microsoft called WinJS. The controls in WinJS (such as GridView, SemanticZoom and so on) are similar to those in XAML and support data bindings too. For more information about WinJS, see bit.ly/winjsbinding. More data-binding frameworks for JavaScript are detailed at bit.ly/jsbinding.
Project Hilo (C++ and XAML)
The third WinRT projection uses XAML as the front end and unmanaged C++ (without the Microsoft .NET Framework) for its logic. Hilo (bit.ly/hilocode) is a sample project from Microsoft patterns & practices aiming to demonstrate the various aspects of creating a Windows Store app with C++ and XAML.
Because of the availability of XAML and data binding, you can use the MVVM pattern with unmanaged C++. Hilo demonstrates how to use MVVM in C++, among other topics such as asynchronous programming in C++; using tiles; page navigation; using touch; handling activation, suspend and resume; creating a high-performance experience; testing the app; and certification.
Hilo comes with the full source code and complete documentation. It’s a good case study for traditional C++ developers wanting to get started in Windows 8 with modern development patterns, as well as for C#/Visual Basic developers who wish to use the extra performance of the C++ stack.
A Reminder About MVVM
The MVVM pattern is a variation of another well-known separation pattern named Model-View-Controller, or MVC. This pattern is used in a multitude of frameworks, notably the widely used Ruby on Rails Web application framework, as well as ASP.NET MVC by Microsoft. It’s used not only in Web applications, but also widely from desktop applications to mobile apps (in iOS, for instance).
The main advantage of a separation pattern is that it assigns clearly defined responsibilities to each of the layers. The model is where the data comes from; the view is what the user is shown and what he actuates. As for the controller, it’s a little like the director of an orchestra, and coordinates the actions and reactions of the application. For instance, the controller is often responsible for the coordination of actions such as displaying data in response to user input, starting and stopping animations, and so on.
With these clearly defined responsibilities, members of the development team can concentrate on each part without stepping on each other’s toes. Similarly, an interaction designer doesn’t have to worry about the creation or persistence of the data and so on.
A nice consequence of the separation of concerns is that decoupled applications are also easier to test. For instance, classes of the model can be unit tested without having to take the view into account. Because the interaction between the model and the view is clearly defined and coordinated by the controller, it’s possible to mock, or simulate, some of these interactions where needed to create consistent test conditions. This is why testability is often mentioned as one of the advantages of using the MVVM pattern in XAML-based applications.
From MVC to MVVM
While the MVC pattern has clear advantages for many frameworks, it’s not the best suited for XAML-based frameworks because of (or thanks to) the data-binding system. This powerful infrastructure can bind properties of different objects and keep them synchronized. While this sounds like a simple feat, the implications are huge: By letting the data-binding system take care of this synchronization, the developer can concentrate on computing the value of data object properties without having to worry about updating the UI.
In addition, a binding is a loose coupling. The binding is only evaluated on demand, and the app doesn’t break if the result of the binding is invalid. This “looseness” can sometimes cause headaches to the developers, because it makes it hard to find why some bindings are not evaluated properly. It is, however, an advantage in order to make it easier to work on the UI without being tightly coupled to a data structure. With loose bindings, it’s very easy to move UI elements on the view and even to completely change an app’s look and feel without touching the underlying layers.
In order to facilitate the data binding and to avoid very large objects, the controller is broken down in smaller, leaner objects called ViewModels, or Presentation Models. A common usage is to pair a view with a ViewModel by setting the ViewModel as the view’s DataContext. In practice, however, this isn’t always the case; it’s not uncommon to have multiple views associated with a given ViewModel, or to have a complex view split in multiple ViewModels.
Thanks to the usage of XAML to build the UI, the data binding can be expressed in a declarative manner, directly in the body of the XAML document. This allows a decoupled process, where the developer worries about the model and the ViewModel, while an interaction designer takes over the creation of the UX at the same time, or even at a later time.
Finally, because XAML is XML-based, it works well with visual tools such as Expression Blend. When configured properly, MVVM makes it possible to visualize design-time data on the screen, which allows the designer to work on the UX without having to run the app, as shown in Figure 1.
Figure 1 Expression Blend for Windows Store Apps with Design-Time Data
The MVVM Light Toolkit
One disadvantage of the MVVM pattern is that some of the code required is what is sometimes called “boilerplate code”—infrastructure code that doesn’t directly perform a function but is required for the internal “plumbing” to work. Probably the best example of boilerplate code is the code needed to make a property observable with the INotifyPropertyChanged interface implementation and its PropertyChanged event, as shown in Figure 2. This code shows that automatic properties (properties with a getter and a setter without body) cannot be used. Instead, the property has a backing field. A check is made in the setter, to avoid raising the PropertyChanged event too often. Then, if the property value does change, the PropertyChanged event is raised.
Figure 2 Observable Property
private string _firstName;
public string FirstName
{
get
{
return _firstName;
}
set
{
if (_firstName == value)
{
return;
}
_firstName = value;
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs("FirstName"));
}
}
}
This is, of course, the worst-case scenario, where every property of an object needs about 20 lines of code. In addition, “magic strings” are used to identify the property’s name, which can cause issues if there’s a typo. In order to solve this, MVVM Light proposes a few solutions:
- The logic needed to raise the PropertyChanged event can be stored in a ViewModelBase class that every ViewModel inherits from.
- Properties can be identified by a lambda expression instead of a string. This prevents typos or errors when the name of the property changes.
- The remaining lines can be automated using a code snippet in Visual Studio.
MVVM Light has quite a few components that are useful to make the creation of decoupled apps faster and easier, as you’ll see in the sample app proposed further in this article.
Windows 8 also introduces a couple new classes to help with this problem, such as the BindableBase class and the CallerMemberName attribute. Unfortunately, these are not available for other XAML-based frameworks and cannot be used in shared code.
Creating a New Application in Windows 8
The easiest way to create a new application is to start Visual Studio 12 and to select the MvvmLight (Win8) project template. After the application is created, it’s possible to start it immediately by pressing Ctrl+F5. The main page is minimal and simply displays “Welcome to MVVM Light,” as shown in Figure 3.
Figure 3 Creating the New MVVM Light Application
What’s more interesting is opening the same app in the Visual Studio Designer: In the Solution Explorer, right-click on the MainPage.xaml and select View Designer. Loading the visuals the first time takes a while, but once everything is ready, the screen shows “Welcome to MVVM Light [design].” Opening the app in Expression Blend also shows the same result: right-click on the same file and select Open in Blend to see the design-time text in the window. Note that Expression Blend for Windows Store apps is installed together with Visual Studio 2012 (even the Express edition). As with Windows Phone before, it’s now possible to use Expression Blend at no cost.
What just happened has some interesting implications: The Visual Designer runs parts of the app, and there’s a way to find out if the app is running in the designer or not. Seeing a different view in the Visual Designer than at run time is a crucial requirement for a good experience during the interaction design. This will allow bypassing Web service calls or database connections that wouldn’t work at design time. It also allows creating well-known data—for instance, very long texts to verify how the layout looks in different orientations or resolutions without having to run the app. This saves time and a lot of trouble during the interaction design phase.
The application being developed is a viewer for a user’s friends, connecting to a Web service inspired by Facebook (but heavily simplified). The Web service returns a JSON-formatted string with information about the user’s friend such as first and last name, date of birth, a URI to a profile picture and so on. This information is stored in an instance of type Friend that’s created in the model layer (the first “M” in MVVM). The Friend class inherits the ObservableObject class provided by the MVVM Light libraries (referenced by the new app). This allows the Friend class to easily raise the PropertyChanged event. Note that this makes sense even though Friend belongs to the model layer—it allows the UI to be data-bound to the Friend’s properties without having to duplicate these properties in the ViewModel layer.
As I mentioned earlier, implementing observable properties requires some boilerplate code, which is annoying but mitigated by MVVM Light: Use a code snippet to add an INPC property (for INotifyPropertyChanged, the interface that defines the PropertyChanged event). Simply type mvvminpcset and then tab to expand the code snippet. Use tab to jump from field to field: enter the property’s name (FirstName), its type (string), the backing field’s name (_firstName) and, finally, the default value (string.Empty). Then type Esc to exit the snippet edit mode. In addition, the snippet adds a constant with the property’s name. This will be useful later when we register to a PropertyChanged event.
All the MVVM Light snippets start with mvvm, which makes it convenient to find them in IntelliSense. There are a few other mvvminpc snippets, for variations of the property’s implementation. Using mvvminpcset, you can also implement an observable property named LastName of type string.
Properties such as FirstName and LastName are quite straightforward. Sometimes, however, the data format that the app gets from the Web service is not optimal, and a conversion needs to take place. In conventional XAML-based development, developers sometimes use a converter (implementation of IValueConverter). In MVVM, however, most converters can be replaced by simple properties. For example, let’s consider the date of birth. The JSON field is in the format “MM/DD/YYYY,” which is the U.S. way to express dates. However, the application might run in any locale, so a conversion is needed.
Let’s start by adding an observable property of type string, named DateOfBirthString, using the same snippet mvvminpcset that was used before. Then, add another property as shown here (this property uses the DateOfBirthString as backing field; it’s in charge of converting the value to a proper DateTime):
public DateTime DateOfBirth
{
get
{
if (string.IsNullOrEmpty(_dateOfBirthString))
{
return DateTime.MinValue;
}
return DateTime.ParseExact(DateOfBirthString, "d",
CultureInfo.InvariantCulture);
}
set
{
_dateOfBirthString = value.ToString("d",
CultureInfo.InvariantCulture);
}
}
One more thing is needed, though: Whenever the DateOfBirthString changes, the PropertyChanged event needs to be raised for DateOfBirth too. This way, data bindings will re-query the value, and force a conversion again. To do this, modify the DateOfBirthString property setter as shown in the following code:
set
{
if (Set(DateOfBirthStringPropertyName,
ref _dateOfBirthString, value))
{
RaisePropertyChanged(() => DateOfBirth);
}
}
The MVVM Light ObservableObject Set method returns true if the value changed. This is the cue to raise the PropertyChanged event for the DateOfBirth property too! This conversion mechanism is quite convenient. The sample app uses it in a few places, such as to convert the profile picture URL (saved as a string) into a URI, for example.
Implementing and Mocking the Data Service
The app already has a simple DataService that can be reused to connect to the actual data service. The Web service is a simple .NET HTTP handler that returns a JSON-formatted file. Thanks to the usage of the asynchronous programming pattern introduced in the .NET Framework 4.5 (async/await keyword), connecting to the Web service is very simple, as show in Figure 4 (together with the IDataService interface). The connection happens in an asynchronous manner, as the SendAsync method name shows. However, thanks to the await keyword, the method doesn’t need a callback that would make the code more complex.
Figure 4 Connecting to the Web Service and Deserializing the JSON Result
public interface IDataService
{
Task<IList<Friend>> GetFriends();
}
public class DataService : IDataService
{
private const string ServiceUrl
= "https://www.galasoft.ch/labs/json/JsonDemo.ashx";
private readonly HttpClient _client;
public DataService()
{
_client = new HttpClient();
}
public async Task<IList<Friend>> GetFriends()
{
var request = new HttpRequestMessage(
HttpMethod.Post,
new Uri(ServiceUrl));
var response = await _client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
var serializer = new JsonSerializer();
var deserialized = serializer.Deserialize<FacebookResult>(result);
return deserialized.Friends;
}
}
Finally, after the JSON string has been retrieved, a JSON serializer is used to deserialize the string into a .NET object of type FacebookResult. This class is just a helper that’s discarded after the method returns.
MVVM Light also includes a simple Inversion of Control (IOC) container called SimpleIoc. An IOC container is a component that is useful not only in MVVM applications, but in any decoupled architecture. The IOC container acts like a cache for instances that can be created on demand, and resolved in various locations in the application.
The DataService implements the IDataService interface. Thanks to the IOC container, it’s easy to mock the data service and create design-time data used in the designer. This class is called DesignDataService, as shown in Figure 5.
Figure 5 Design-Time Data Service
public class DesignDataService : IDataService
{
public async Task<IList<Friend>> GetFriends()
{
var result = new List<Friend>();
for (var index = 0; index < 42; index++)
{
result.Add(
new Friend
{
DateOfBirth = (DateTime.Now - TimeSpan.FromDays(index)),
FirstName = "FirstName" + index,
LastName = "LastName" + index,
ImageUrl = "https://www.galasoft.ch/images/el20110730009_150x150.jpg"
});
}
return result;
}
}
Registering and Calling the Services
Now that the services are implemented, it’s time to instantiate them and create the ViewModels. This is the ViewModelLocator class task. This class is quite important in the application structure enabled by MVVM Light. It’s created as a XAML resource in the file App.xaml. This creates the important link between XAML markup and source code, allowing the visual designers to create the ViewModels and to run the design-time code. The registration is shown in Figure 6.
Figure 6 Registering the Services and ViewModels
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IDataService,
Design.DesignDataService>();
SimpleIoc.Default.Register<INavigationService,
Design.DesignNavigationService>();
}
else
{
SimpleIoc.Default.Register<IDataService, DataService>();
SimpleIoc.Default.Register<INavigationService>(() =>
new NavigationService());
}
SimpleIoc.Default.Register<MainViewModel>();
}
Because the MainViewModel constructor takes an IDataService and an INavigationService as parameters, the SimpleIoc container is able to create all the objects automatically. The MainViewModel is exposed as a property of the ViewModelLocator and data-bound in XAML to the MainPage’s DataContext. This binding is already created in the MVVM Light project template. When the page is opened in Expression Blend, the data binding is resolved, the MainViewModel instance is created (if needed) and the constructor is run, with the correct instance of the DataService (either runtime or design time).
The action of calling the data service is exposed with a RelayCommand, shown in Figure 7. This class is a component of the MVVM Light Toolkit that implements the ICommand interface and offers an easy way to bind the Command property of a UI element (such as a Button) to a method implemented on the ViewModel.
Figure 7 The RelayCommand Class
private RelayCommand _refreshCommand;
public RelayCommand RefreshCommand
{
get
{
return _refreshCommand
?? (_refreshCommand =
new RelayCommand(ExecuteRefreshCommand));
}
}
private async void ExecuteRefreshCommand()
{
var friends = await _dataService.GetFriends();
if (friends != null)
{
Friends.Clear();
foreach (var friend in friends)
{
Friends.Add(new FriendViewModel(friend, _schema));
}
}
}
The Friends collection to which the friends are added is of type ObservableCollection<FriendViewModel>. This collection type is often used in XAML-based frameworks, because any list control data-bound to such a collection automatically updates its view when its content changes. Instead of directly storing instance of the model’s Friend class into the collection, they’re wrapped into another class of the ViewModel layer called FriendViewModel. This allows adding view-specific properties that won’t be persisted in the model. For instance, the FriendViewModel class exposes a property named FullName. Depending on the application’s settings, it can return a string in the format “FirstName, LastName” or “LastName, FirstName.” This kind of logic is typical from ViewModel classes and shouldn’t be stored in the lower layers of the application.
In order to return the FullName property in the correct format, the FriendViewModel listens to a message of type ChangeFullNameSchemaMessage. This is done thanks to the Messenger component of MVVM, a loosely coupled event bus connecting a sender and a series of recipients without creating a strong connection between them. Note that the Messenger can send any message type, from simple values such as an int to complex objects with additional information.
When such a message is received, the PropertyChanged event is raised for the FullName property. The FriendViewModel class is shown in Figure 8.
Figure 8 The FriendViewModel Class
public class FriendViewModel : ViewModelBase
{
private FullNameSchema _schema = FullNameSchema.FirstLast;
public Friend Model
{
get;
private set;
}
public FriendViewModel(Friend model, FullNameSchema schema)
{
Model = model;
Model.PropertyChanged += (s, e) =>
{
if (e.PropertyName == Friend.FirstNamePropertyName
|| e.PropertyName == Friend.LastNamePropertyName)
{
RaisePropertyChanged(() => FullName);
return;
}
if (e.PropertyName == Friend.DateOfBirthPropertyName)
{
RaisePropertyChanged(() => DateOfBirthFormatted);
}
};
Messenger.Default.Register<ChangeFullNameSchemaMessage>(
this,
msg =>
{
_schema = msg.Schema;
RaisePropertyChanged(() => FullName);
});
}
public string DateOfBirthFormatted
{
get
{
return Model.DateOfBirth.ToString("d");
}
}
public string FullName
{
get
{
switch (_schema)
{
case FullNameSchema.LastFirstComma:
return string.Format(
"{0}, {1}",
Model.LastName, Model.FirstName);
default:
return string.Format(
"{0} {1}",
Model.FirstName, Model.LastName);
}
}
}
}
The instruction to switch from “FirstName, LastName” to “LastName, FirstName” is sent by the MainViewModel as shown here:
private void SetSchema(FullNameSchema schema)
{
_schema = schema;
Messenger.Default.Send(new
ChangeFullNameSchemaMessage(_schema));
}
Because of the decoupled manner with which the Messenger class is operating, it would be very easy to move it from the MainViewModel; into a Settings class at a later point, for example.
Setting up Navigation
Navigation between pages in Windows 8 is quite easy when it’s initiated from the view’s codebehind, thanks to the NavigationService property that every Page exposes. In order to navigate from the ViewModel, however, a little setup is needed. It’s quite easy, because the Frame that’s responsible for the navigation is exposed in a static manner as ((Frame)Window.Current.Content). The application can expose a standalone navigation service:
public class NavigationService : INavigationService
{
public void Navigate(Type sourcePageType)
{
((Frame)Window.Current.Content).Navigate(sourcePageType);
}
public void Navigate(Type sourcePageType, object parameter)
{
((Frame)Window.Current.Content).Navigate(sourcePageType, parameter);
}
public void GoBack()
{
((Frame)Window.Current.Content).GoBack();
}
}
The code in Figure 8 shows how the navigation service is registered with the SimpleIoc container. It’s injected as a parameter in the MainViewModel constructor, and can be used to conveniently start a UI navigation directly from the ViewModel layer.
In the MainViewModel, the navigation is initiated when the property called SelectedFriend changes. This property is an observable property just like others that were set up earlier. This property will be data-bound in the UI, so the navigation is initiated by the user’s actions. To display the friends, a GridView is used, and it’s data-bound to the Friends collection on the MainViewModel. Because this ViewModel is set as the MainPage DataContext, the binding is easy to create, as shown here:
<GridView
ItemsSource="{Binding Friends}"
ItemTemplate="{StaticResource FriendTemplate}"
SelectedItem="{Binding SelectedFriend, Mode=TwoWay}"/>
Another TwoWay binding is created between the GridView SelectedItem property and the MainViewModel SelectedFriend property listed in Figure 9.
Figure 9 The MainViewModel SelectedFriend Property
public const string
SelectedFriendPropertyName = "SelectedFriend";
private FriendViewModel _selectedFriend;
public FriendViewModel SelectedFriend
{
get
{
return _selectedFriend;
}
set
{
if (Set(SelectedFriendPropertyName,
ref _selectedFriend, value)
&& value != null)
{
_navigationService.Navigate(typeof (FriendView));
}
}
}
Finally, the navigation leads the user to a details page for the selected Friend. In this page, the DataContext is bound to the MainViewModel SelectedFriend property. This, again, ensures a good design-time experience. Of course, at design time the RefreshCommand is executed when the MainViewModel is constructed, and the SelectedFriend property is set:
#if DEBUG
private void CreateDesignTimeData()
{
if (IsInDesignMode)
{
RefreshCommand.Execute(null);
SelectedFriend = Friends[0];
}
}
#endif
At this point, the UX can be designed in Expression Blend. Because the design-time code is run, Blend displays all the design-time friends in a GridView added to the MainPage, as was shown in Figure 1. Of course, creating the data templates takes some time and skill, but it can be easily done in a visual manner without having to run the application.
Wrapping Up
All of this may seem quite familiar to developers familiar with the MVVM pattern in WPF, Silverlight or Windows Phone. That’s because things are similar with the Windows Runtime. The skills acquired in those previous frameworks are easily transferable to Windows Store app development. Of course, some concepts (such as the asynchronous programming with async/await) are new, and some work is needed to convert code to the Windows Runtime. But with the MVVM pattern and helpers such as the MVVM Light Toolkit, developers get a good head start and can fully enjoy the advantages of a decoupled application pattern.
Laurent Bugnion is senior director for IdentityMine Inc., a Microsoft partner working with technologies such as Windows Presentation Foundation, Silverlight, Surface, Windows 8, Windows Phone and UX. He’s based in Zurich, Switzerland.
Thanks to the following technical experts for reviewing this article: Karl Erickson and Rohit Sharma