Sunday, September 25, 2011

MVVM Step By Step, part I

Since we are doing quite a lot of Silverlight, WPF and Windows Phone 7 development at QFrame, we also train our new people in patterns like MVVM. For future reference I thought it would be nice to write the basics of our MVVM session down. It is actually a step by step approach to implementing MVVM in a Silverlight application (which is usable in WPF and Windows Phone development as well). I also don't use any predefined framework in the initial explanation of the MVVM pattern. This is to let you see what can be done without using frameworks and for which parts some library functionality might be nice.

As a startup, I will create a simple Silverlight application which is hosted in a ASP .NET web application. In the ASP .NET web application I will also place a small WCF Data Service, which will provide the model data I will use in the Silverlight MVVM app. The database (a simple mdf file) contains two tables customers and companies. I created an Entity Data Model for these in the ASP .NET web application and hosted them in a WCF Data Service. The data service looks like this:

public class CustomerService : DataService<CustomersEntities>
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(DataServiceConfiguration config)
        config.SetEntitySetAccessRule("Customers", EntitySetRights.All);
        config.SetEntitySetAccessRule("Companies", EntitySetRights.All);
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;

This is the initial project setup:

The service reference to the CustomerService is already present in the Silverlight project.

First thing I do in a new MVVM application, is creating separate folders for my models, views and viewmodels. In this demo, my model will consist of simple data classes, but actually my service is also part of my model. My models, viewmodels and views will all be placed in the same project, but this is not a necessity.

For the application I am building, I want a kind of menu on the left of the screen, with links to, for instance, an 'all customers' page, a 'new customer' page, an 'all companies' page and a 'new company' page. On the right of the page the corresponding page will be shown. To achieve this, I will create a new view, called MainView.xaml in which I place a couple of buttons and a ContentPresenter.

<UserControl x:Class="Demo1.Views.MainView"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White">
            <ColumnDefinition Width="30*" />
            <ColumnDefinition Width="70*" />
        <StackPanel Grid.Column="0" Background="AliceBlue">
            <Button Content="All Customers" Margin="10" />
            <Button Content="New Customer" Margin="10" />
            <Button Content="All Companies" Margin="10" />
            <Button Content="New Company" Margin="10" />
        <ContentPresenter Grid.Column="1" />

Now, since we are using MVVM, I also need to create a viewmodel to go with this view. So, in the ViewModels directory I will create a new class and call it MainViewModel.

namespace Demo1.ViewModels
    public class MainViewModel

We now have our view and our viewmodel. If we'd run this application now, this wouldn't show much on our screen yet. In fact, you would see a blanc page. This is because the application is still wired up to show the default xaml page. Open up your app.xaml.cs file and you'll see the following piece of code.

private void Application_Startup(object sender, StartupEventArgs e)
    this.RootVisual = new MainPage();

This will have to be changed so your MainView is set to the RootVisual of the application. And also, the view (MainView) and viewmodel (MainViewModel) will have to be linked to each other. Now, for this, there are two options. Either your view knows who its viewmodel is (view-first) or it doesn't (viewmodel-first). I will use the viewmodel-first approach.

To link the two up, change the default code in app.xaml.cs as follows:

private void Application_Startup(object sender, StartupEventArgs e)
    var view = new MainView();
    var viewmodel = new MainViewModel();
    view.DataContext = viewmodel;
    RootVisual = view;

If you would do this linking view-first, you would set the DataContext property in the xaml of your view. In this demo I've chosen to use the viewmodel-first approach.

After doing this, and running the application, you will get to see your view. pressing the buttons, however, will not have much effect, yet. We will make them send messages to your viewmodel in the next part.

No comments:

Post a Comment