Integrating ViewModel Classes into Silverlight Applications

Use the Model-View-ViewModel architecture platform

Downloads
102936 Code.zip

Click here to download the code for this article.

There have been a lot of software architecture patterns proposed over the years that aim to simplify development, minimize maintenance costs, and allow code to be re-used more efficiently. The pros and cons of patterns such as MVP, MVC, and MVVM are discussed frequently in Internet forums with strong opinions being expressed both in favor of and against each. What pattern should be used to build a particular application? Is it a "testable" pattern, and will the pattern hold up as new technologies are rolled out? Unfortunately, there's no "one size fits all" answer to these questions.

With the continued rise of Silverlight as an application development framework, the discussion of patterns has grown from a low hum to a loud roar. The majority of developers building Silverlight applications have agreed on a pattern that fits well in the Silverlight world called Model-View-ViewModel (MVVM). The MVVM pattern allows applications to be divided up into separate layers that provide multiple benefits ranging from better code re-use to enhanced testing capabilities. This article will explain key concepts found in the MVVM pattern. Once the concepts are covered from a theoretical standpoint, you'll be shown how code that follows the MVVM pattern can be used in Silverlight applications.

Introduction to the MVVM Pattern
There are three main parts to the MVVM pattern: the Model, the View, and the ViewModel. Figure 1 shows a slide from a Silverlight course my company wrote that sums up the role of each part of the MVVM pattern in a concise and simple way.

Looking at Figure 1, you can see that the Model represents the business domain which includes the model classes used (Customer, Order, etc.), data access code, and business rules. In general you can think of the Model as representing the entities that live on the server, as well as the objects that are responsible for interacting with the data store your application uses and filling entities with data. While some people feel that the Model represents only the model classes (Customer, Order, etc.) used in the application, I personally think of it more broadly to include data access code and business rules. Silverlight applications will call into the Model code through services written using WCF, ASMX, REST, or even custom solutions.

The View in MVVM represents the Silverlight screens that you build. This includes the XAML files and the code-beside files that are responsible for showing data to end users. The View's responsibilities include displaying data and collecting data from end users. A given View isn't responsible for retrieving data, performing any business rules, or validating data.

The ViewModel acts as the middle-man between the View and the Model. It's responsible for aggregating and storing data that will be bound to a View. For example, a ViewModel may contain a List<State> property and a List<Person> property that can be bound to two ComboBox controls in a View. The ViewModel will retrieve the values held by these two properties from the Model. By using a ViewModel, the View doesn't have to worry about retrieving data and knows nothing about where data comes from.

Additional players may be added into the Model-View-ViewModel mix to help segregate code even further. For example, I normally create a service agent class that is responsible for making calls from Silverlight to remote services. The service agent is responsible for initiating the service call, capturing the data that's returned, and forwarding the data back to the ViewModel. By doing this, the ViewModel classes can delegate data gathering responsibilities to the service agent. A given service agent can also be re-used across multiple ViewModel classes as needed. Figure 2 shows how the service agent can be integrated into the MVVM pattern.

When developers first start building Silverlight applications, they typically add all of the code for the application into the XAML's code-beside file (MainPage.xaml.cs, for example). Although this approach certainly works, you can take advantage of several inherent benefits by following the MVVM pattern, including better code re-use, simplified maintenance, more modular code, and enhanced testing support. I'll focus on the overall benefits achieved by building applications that are based on the MVVM pattern throughout the rest of this article.

Creating the Model
There are many different ways that the Model can be created, such as using Microsoft's Entity Framework or LINQ to SQL technologies, nHibernate, PLINQO, SubSonic, and custom solutions. The technology chosen is generally unique to a given company's development policies, so I'm not going to go into a discussion of the pros and cons of each technology here. What's important is that one or more classes used by a Silverlight application are "modeled" using tools or by writing code by hand. This involves defining all of the properties that each class will expose. A simple example of a Model class is shown in Figure 3.

Once the Model classes are in place, they'll need to be populated with data from a data store. This can be done by writing custom code or using ORM frameworks that handle mapping query results to object instances. Services will also need to be written to expose one or more of the Model classes used in a Silverlight application, which can be done using WCF, ASMX, or even custom REST services.

Creating View and ViewModel Classes
Once the Model is ready to go, the View and ViewModel classes can be created. As mentioned earlier, a View represents a Silverlight screen that end users interact with that includes the XAML file and the associated code-beside file. Rather than adding all of the code to call the Model and retrieve data directly into the View's code-beside file, the View will rely on a ViewModel class to retrieve data and then bind to the properties of the ViewModel.

ViewModel classes need to implement an interface that's available in Silverlight called INotifyPropertyChanged, which defines a single event named PropertyChanged. This event is used to notify different Silverlight bindings that data has changed for one or more properties so that controls can be updated automatically. Although INotifyPropertyChanged can be implemented directly on a ViewModel class, your application may have multiple ViewModel classes in it and writing the same code over and over tends to get old. Creating a base ViewModel class that handles implementing INotifyPropertyChanged is useful to minimize code and allow more re-use to occur in applications. Figure 4 shows a class named ViewModelBase that implements the INotifyPropertyChanged interface. The class also provides an OnNotifyPropertyChanged method that can be used to raise the PropertyChanged event.

A ViewModel class can derive from ViewModelBase and automatically take advantage of the INotifyPropertyChanged interface. Figure 5 shows an example of a ViewModel class named PeopleViewModel that derives from the ViewModelBase class. Looking through the code, you'll see that PeopleViewModel defines two fields and two properties. Each property raises the PropertyChanged event as the set block is called by calling the OnNotifyPropertyChanged method defined in ViewModelBase. This notifies any controls bound to the properties that the values have changed, which allows them to update the data they display automatically.

Defining properties in a ViewModel is a good first step, but the ViewModel needs a way to get data from the Model into the properties. Although code can be added directly into a ViewModel to call services that provide Model object data, I prefer to make the calls through the service agent class mentioned earlier. A service agent handles calling services and then passing data that is retrieved back to the ViewModel so that it can be assigned to the appropriate properties.

An example of a service agent class capable of calling two WCF service operations is shown in Figure 6, along with an interface that the service agent implements. This particular service agent makes calls to a WCF service using a proxy object that was generated in Visual Studio using the Add Service Reference tool.

The GetPeople and UpdatePerson methods shown accept the parameters that each service operation requires, as well as a callback method that will be invoked once the data returns. This allows the ViewModel to call into the service agent to retrieve the data it needs and then be notified once the data is available. Figure 7 shows an example of using the service agent in the PeopleViewModel class shown earlier in Figure 5.

Looking at the first constructor in the code, you'll see that it forwards the call to a secondary constructor that accepts a parameter of type IServiceAgent, which was defined in Figure 5. Why have two constructors? This approach allows testing frameworks to pass in different types of service agents to the ViewModel when running tests. When the ViewModel is called at runtime, the constructor (without parameters) will be called and an instance of the ServiceAgent class shown in Figure 6 will be passed as the IServiceAgent parameter. Although I won't discuss the concept of dependency injection (DI) here, the constructor pattern shown here lends itself well to that type of functionality when it's needed.

Once the service agent object is passed into the ViewModel's constructor, a call to a method named GetPeople is made which invokes a method on the service agent and passes a callback delegate. The WCF service is then called by the service agent and the results are returned to the GetPeople_Completed method within the ViewModel which assigns the value to the People property. Note that the standalone callback methods (GetPeople_Completed and UpdatePerson_Completed) can be simplified by using lambdas. An example of simplifying the GetPeople method from Figure 7 is shown next

   public void GetPeople()

\\{

   _ServiceAgent.GetPeople((s,e) => this.People = e.Result);

\\}

If you're new to patterns such as MVVM, it may seem like there are a lot of moving parts in the overall architecture at this point, given the ViewModelBase, ViewModel, and ServiceAgent classes. However, after a little practice and experimentation with the pattern, I think you'll find that this approach is great for maximizing code re-use, maintaining code in team environments, and providing a flexible framework for testing.

Binding a ViewModel to a View
Now that the ViewModel class is defined, it can be bound to a View. This can be done declaratively in XAML or imperatively through code in the View's code-beside file. Imperative binding is typically accomplished by assigning a ViewModel instance to the layout root's DataContext property, as shown in the code below

this.LayoutRoot.DataContext = new PeopleViewModel();

An example of declaratively binding a ViewModel to a View is shown in Figure 8.

The ViewModel namespace is first referenced using an XML namespace prefix of "viewModel". The ViewModel is then defined in the UserControl's Resources section and given a key of "ViewModel" (note that any name can be chosen for the key). The key is important since it's used to hook the ViewModel to the DataContext of the layout root using the \\{Binding Source=\\{StaticResource ViewModel\\}\\} syntax.

The declarative binding will cause a new PeopleViewModel instance to be created at runtime, which is then bound to the layout root's DataContext. Child controls of the layout root can then bind to properties on the ViewModel. An example of binding a ListBox to the ViewModel's People property and a StackPanel to the Person property is shown in Figure 9.

Conclusion
The MVVM pattern provides a flexible way to work with data that encourages code re-use and simplifies maintenance. In this article you've seen the role that the Model, View, and ViewModel can play in a Silverlight application, as well as how a ViewModel class can be created. You've also seen how a ViewModel can be bound to a Silverlight View using declarative techniques. There's much more that can be discussed with regard to the MVVM pattern in Silverlight (such as event buses, commanding, and dependency injection) but I hope that this article helps jumpstart the process of architecting and developing Silverlight applications. If you have specific Silverlight development concepts you'd like to see covered in future articles, send a tweet @DanWahlin.

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish