Hands-on MVVM 1: Model and View

I will be presenting this material at Dallas XAML tomorrow (May 4, 2010). If you are in the area, please come by. If not, just download the demo code and follow along.

Microsoft has finally nailed data binding in WPF and Silverlight. It has long been ridiculed as a demo-only feature. But now it is useful in real application development.

As people apply data binding to real applications, patterns have emerged. One of the most prevalent is Model-View-ViewModel. In truth, MVVM is not just one pattern. It is a collection if interrelated patterns. Each person has a different idea of what MVVM actually looks like. This is my opinion.

The goal of this series is to understand why it is good to follow these patterns. We are going to start with direct data binding. We won’t add any code until we need it. When we find that things don’t work, we’ll add code to make them work. When things start to get messy, we will refactor to clean them up.

The model
The application that we are building keeps track of people. It starts innocently enough with a class called Person:

public class Person
{
    private string _firstName;
    private string _lastName;
    private string _email;
    private string _phone;

    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }

    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; }
    }

    public string Email
    {
        get { return _email; }
        set { _email = value; }
    }

    public string Phone
    {
        get { return _phone; }
        set { _phone = value; }
    }
}

Notice that this class does not implement INotifyPropertyChanged. We are starting simple so we know why we need that code.

The view

We’ll data bind our view directly to our model. Data binding works against properties. The Person user control defines one text box for each Person property.

<UserControl x:Class="Step1.View.PersonUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="#FF353535">
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Target="{Binding ElementName=firstName}" Content="_First Name:"/>
        <Label Grid.Row="1" Target="{Binding ElementName=lastName}" Content="_Last Name:"/>
        <Label Grid.Row="2" Target="{Binding ElementName=email}" Content="_Email:"/>
        <Label Grid.Row="3" Target="{Binding ElementName=phone}" Content="_Phone:"/>

        <TextBox Grid.Row="0" Grid.Column="1" x:Name="firstName" Text="{Binding FirstName}"/>
        <TextBox Grid.Row="1" Grid.Column="1" x:Name="lastName" Text="{Binding LastName}"/>
        <TextBox Grid.Row="2" Grid.Column="1" x:Name="email" Text="{Binding Email}"/>
        <TextBox Grid.Row="3" Grid.Column="1" x:Name="phone" Text="{Binding Phone}"/>
    </Grid>
</UserControl>

Notice that the view only contains layout and controls. All of the styling is expressed in App.xaml.

The application

The view needs an instance of the model to bind to. Our application will load this instance from a data source – most likely a database or a web service – and give it to the view. The view is hosted within a window. This is all accomplished in Application_Startup.

DataSource dataSource = new DataSource();
this.MainWindow = new PersonWindow();
this.MainWindow.DataContext = dataSource.GetPerson();
this.MainWindow.Show();

Again, we are keeping it simple. There is no dependency injection. There is no service locator. If we see that we need that code, we will add it.

person_window When you run this program, the Person window appears. It is bound to the person that we loaded from the data source. When you edit the properties of a person, your changes are set directly into the model.

The code is extremely simple, and it worked out-of-the-box. So far we haven’t seen a need to implement INotifyPropertyChanged. Strictly speaking, that interface is not necessary for data binding to work. But very soon we will run into situations in which it is necessary.

Also, we have not yet created a ViewModel. It is not strictly necessary for getting an application working. But again, we will soon see a situation in which it makes our code much cleaner.

In part 2, we will add features to this application. Let’s see how those features look when we bind the view directly to the model.

Leave a Reply

You must be logged in to post a comment.