Silverlight Model-View-ViewModel in Action

An introduction to using Silverlight MVVM, with code examples

Downloads
136416_Haidar_MVVM.zip

Following the best practices or proper techniques to develop with a technology is a major task that developers and architects focus upon when working on their applications. This task even becomes more crucial and critical when dealing with a new technology that is paving its way for success.

The rule is simple: Separating concerns in an application always works fine for most frameworks as this helps in:

  • maintaining the application easily in the future
  • making it easier to test the application
  • tracing/detecting bugs while making developing faster
In WPF and Silverlight, one of the best practices to follow is the Model View ViewModel (MVVM) design pattern. Throughout this article you will see a practical example on how to apply the MVVM in Silverlight applications.

MVVM Background


This article focuses on showing the technical details on implementing the MVVM design pattern. If you are interested in reading more on this design pattern it is recommended to read this article that explains MVVM and how to apply it on a WPF application.

MVVM in Action


The application to be developed is a simple one that displays a Silverlight form to submit a new appointment for a client.

The fields on the form are:
1.    Client ID: Client's unique ID. This field is read-only.
2.    First Name: Client's First Name
3.    Last Name: Client's Last Name
4.    From time: Start time of an appointment
5.    To time: End time of an appointment
6.    Day: weekday of an appointment

For an appointment to be created successfully, the client's last name must be filled in. This is just a simple rule that has no effect on the MVVM implementation; I just added it to show how feedback can be sent back to the UI in both cases success and failure.

The solution is divided into server- and client-side folders.

1.    Server side:
The server side, that is, the ASP.NET side, has two main web projects:
a.    Silverlight.View.Web: the ASP.NET application that will host the Silverlight application.
b.    Server.Host: the ASP.NET application to host a WCF service used later on by the Silverlight application. This project separates the development of the WCF into several folders, as follows:
i. DataContracts: This folder contains all the domain-transfer-objects that will be exchanged between the WCF and the Silverlight client.
ii. ServiceContracts: This folder contains the C# interfaces that represents the "What" or available functionality of the WCF service.
iii. Implementation: This folder contains the C# class implementing the service contracts defined above representing the "How" or the real implementation of the functionality of the WCF service.
In addition, the WCFservice is hosted inside the Appointment.svc file that is simply bound to the above service implementation.

2.    Client side:
The client side, that is, the Silverlight side in this scenario, has several sub projects representing those of the MVVM design pattern:

a.    Silverlight.Model: This is the Model part of the Silverlight application. It is here where the dirty code to query the server and retrieve the data is written. Hence this project adds a service reference to the server-side WCF host.
b.    Silverlight.ViewModel: The ViewModel is the mediator between the View and Model in MVVM. This layer is aware of the model layer, where it communicates with the model to retrieve the data from it, if required converts the data into other formats, populates properties that are bound to controls on the View layer, handles the UI logic, and much more.
c.    Silverlight.View: This is the View part of the Silverlight application. This is required to present the UI of the application. In Silverlight the notion of Commanding—the ability to delegate handling UI logic into the ViewModel layer—is missing. Therefore, until Commanding is implemented in C#, the View layer shall handle the UI logic. Commanding can be easily used in Silverlight when using the Composite Application Library (CAL) provided by the Microsoft best practices department.
d.    Silverlight.Common: This project functions as the infrastructure layer where common classes, interfaces, events and methods are placed and accessible by the rest of projects on the client side.


Model Layer Implementation


This layer defines a C# interface, dictating the methods and events to be implemented by this layer as follows:


namespace Silverlight.Model
{
    public interface IAppointmentOperations
    {
        void StoreAppointmentAsync(Appointment appointment);

        event EventHandler StoreAppointmentCompleted;
        event EventHandler<StoreAppointmentFailedEventArgs> StoreAppointmentFailed;
    }
}


For sake of simplicity and to keep the focus on MVVM, only a single method exists, which accepts as input an instance of an Appointment DTO and returns nothing. In addition, two events are defined and that will be fired upon both the successful and unsuccessful creation of an appointment in the system.

It is recommended that you define the functionality of the model layer in an interface. This helps later on in testing the ViewModel layer where a model mock object could be provided for the sake of testing. This way if bugs appear then for sure coming up from the ViewModel since the model implementation is a dummy one.

A reference to the WCF located in the server side is added to this project and used in the implementation of the above interface. Figure 1 shows the code.

The AppointmentModel class representing the Model layer:

1.    implements the IAppointmentOperations interface.
2.    provides an empty constructor.
3.    includes the implementation of the StoreAppointmentAsync method. This method simply hooks into the StoreAppointmentCompleted event, creates a new instance of the WCF proxy, and calls the same method on that proxy.
4.    includes the implementation of the StoreAppointmentCompleted event handler. It is inside the StoreAppointmentCompleted event handler method that the proper success/failure event is fired and handled by the ViewModel layer.

ViewModel Layer Implementation

The ViewModel layer includes all properties, methods, events, and command logic implementation that the View layer asks for. For doing so, the ViewModel accepts an instance of the Model to provide whatever the view needs. This layer defines a C# interface dictating the methods and events to be implemented by this layer and that are accessible by the View layer:

public interface IAppointmentViewModel
    {
        void StoreAppointment();
        Appointment CurrentAppointment { get; set; }
        event EventHandler StoreAppointmentCompleted;
        event EventHandler<StoreAppointmentFailedEventArgs> StoreAppointmentFailed;
    }

The StoreAppointment() method located inside the ViewModel class is called upon submitting the form. This is done either by directly calling it through the event handler of a Button, or, in the presence of commands, the command delegate method will call it to submit and create a new Appointment.

In addition, the CurrentAppointment property represents a single loaded Appointment. This property will be bound to the controls on the View layer. Thus, changing any field's value on the View layer automatically changes the value of that field inside this property.

Additionally, two events are defined that the View layer can subscribe to when a success/failure operation happens.

The AppointmenViewModel class representing the ViewModel layer:

1.    implements the IAppointmentViewModel interface.
2.    inherits from the ViewModelBase class. This class implements the INotifyPropertyChanged interface and provides methods to signal to the View layer that a change happened in the source data. This way, all the ViewModel classes in your application can inherit from that class without your having to retype all code related to property change.
3.    provides a constructor accepting an interface of type IApplicationOperations. This is the interface that the Model layer implements. This way, a different Model implementation can be supplied into the ViewModel class, which is helpful in testing.
4.    provides an empty constructor that automatically calls the other constructor passing a new instance of the AppointmentModel class. 5.    implements the methods/properties/events defined in the IAppointmentViewModel interface. The implementation of the StoreAppointment() method is simply a call to the model's StoreAppointment() method. Here business rules can be applied on the data before sending it to the model.



The events fired by the Model layer are handled by the ViewModel. The ViewModel doesn't simply fire them into the View layer. While doing so, the ViewModel makes sure that the events are fired on the same UI thread of that of the View layer. For this reason, you can see what the OnStoreAppointmentCompleted (or OnStoreAppointmentFailed) event handler looks like:

private void OnStoreAppointmentCompleted()
        {
            Dispatcher dispatcher = null;
            if (Deployment.Current != null)
            {
                dispatcher = Deployment.Current.Dispatcher;
            }

            EventHandler temp = this.StoreAppointmentCompleted;
            if (temp != null)
            {
                if (dispatcher != null && !dispatcher.CheckAccess())
                {
                    dispatcher.BeginInvoke((Action)OnStoreAppointmentCompleted);
                }
                else
                {
                    // Storing a new appointment complete
                    temp(this, this.completeArgs);
                }
            }
        }

The code above makes sure the event fired to the View layer is done on the UI thread and not any other thread by using the BeginInvoke() method of the Dispatcher class. This is important so that you don't get a "Cross-thread" exception in your code.

View Layer Implementation

The View in the MVVM represents the application's user interface (UI). It is made up mainly of XAML, where it binds the controls to the properties inside the ViewModel and hooks to events fired by the ViewModel. In frameworks that support commanding, like CAL, the View also fires commands that get handled by the ViewModel layer. For the sake of our sample application, the XAML is as follows:

<UserControl …  
    xmlns:vm="clr-namespace:Silverlight.ViewModel;assembly=Silverlight.ViewModel">
    <UserControl.Resources>
        <vm:AppointmentViewModel x:Key="viewModel" />
    </UserControl.Resources>
  <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource viewModel}}">
            …
                        <TextBox IsEnabled="False"
                                 x:Name="txtClientID"
                                 Grid.Column="1"
                                 Grid.Row="0"
                                 Width="300" Text="{Binding CurrentAppointment.ID, Mode=TwoWay}"
                                 HorizontalAlignment="Left"
                                 Margin="10,0,0,0" />
                        …               
                        <Button x:Name="btnSubmit" Margin="0,10,0,0"
                                Content="Create new Appointment"
                                Padding="10"  />
                …
    </Grid>
</UserControl>

This XAML does the following:

1.    Adds a namespace reference into the ViewModel namespace.
2.    Add a resource defining an instance of the AppointmentViewModel inside the UserControl's Resources collection.
3.    Sets the Binding on the Grid's DataContext to the instance of the ApplicationViewModel using a StaticResource markup extension.
4.    Sets the Binding (Path and Mode) on each TextBox to a specific property on the CurrentAppointment object exposed by the ViewModel representing a single Appointment object. Since Silverlight doesn’t support Commanding out of the box yet, the code-behind is utilized to supply an event handler for the Button used to submit the form:

// Subscribe to the Submit button
        this.btnSubmit.Click += new RoutedEventHandler(btnSubmit_Click);
        
       void btnSubmit_Click(object sender, RoutedEventArgs e)
        {
            this.localViewModel.StoreAppointment();
        }

The event handler simply calls the StoreAppointment() method exposed by the ViewModel:

this.localViewModel = this.Resources["viewModel"] as VM.AppointmentViewModel;
            this.localViewModel.StoreAppointmentCompleted += new EventHandler(viewModel_StoreAppointmentCompleted);
            this.localViewModel.StoreAppointmentFailed += new EventHandler<StoreAppointmentFailedEventArgs>(viewModel_StoreAppointmentFailed);



The "viewModel" instance is retrieved from the XAML and casted to an object of type AppointmentViewModel class, and then the events are hooked up.

Summing Up


Once you understand the concept behind MVVM, you can continue using it to improve your application development. To recap, the MVVM can be explained as follows:
1.    Model layer handles all data layer interactions.
2.    ViewModel layer talks to the Model layer to retrieve data from and exposes methods/properties/events to be handled by View layer.
3.    View layer displays the UI of the application and interacts with the ViewModel for binding and handling UI logic.

One you are familiar with developing using MVVM, you should then look at the CAL to better architecture your application based on UI composition, modularity, commanding, and global event handling.

Bilal Haidar ( [email protected]) is a Microsoft MVP in ASP.NET. He is an MCP, MCTS, MCPD, MCT, and Telerik MVP. He is a senior software developer at CCC, a multinational construction company based in Athens, Greece.
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