Archive for May, 2010

Find one solution to many problems

Tuesday, May 25th, 2010

I’m working on a graphical editor in WPF. One feature of this editor is the ability to resize an object. As cool as that feature is, the comment I got from my partner on the project was even better.

In this editor, you can drag the mouse across the surface to pan. You can use your scroll wheel to zoom in and out. And you can select an object and use your scroll wheel to resize it. The trick is figuring out just how much to resize with every tick.

When the scale is zoomed out, you want each tick of the mouse to adjust the size by large amount. When the scale is zoomed in tight, you want to adjust by a proportionally smaller amount. This gives the user a chance to fine-tune by zooming in.

image

image

But on the other end of the spectrum, you have to prevent the size of the object from reaching zero. So when the object gets small, it no longer shrinks in proportion to the zoom.

image

Design an equation
The first problem is to change the size in proportion to the zoom. The easiest way to do this is to convert the object size into screen size, adjust by a constant amount, and then convert back. Here’s the math to do that:

  • Screen size = actual size * zoom factor
  • New screen size = screen size + ticks * pixels per tick
  • New actual size = new screen size / zoom factor

The second problem is to switch modes when the object appears small on the screen. Instead of changing screen size by a fixed number of pixels per tick, you want to change by fewer pixels as the object gets smaller. This way you will approach zero but never actually reach it.

The key to solving this second problem is that idea of approaching a target without reaching it. In mathematical terms, that target – or limit – is an asymptote. We want to design an equation that asymptotically approaches zero as we scale down. But at the same time, we want to asymptotically approach a constant growth as we scale up. Here are the two asymptotes:

  • y = 0
  • y = x

The first asymptote (y = 0) makes the size of our object to approach zero but never actually reach it. The second asymptote (y = x) makes the size of the object to increase by the same amount each time we tick the scroll wheel. Let y be the screen position, and all this happens relative to the zoom.

To design an equation with asymptotes, simply multiply to make each one a root of the equation:

  • (y – 0) * (y – x) = 0

The first factor represents the first asymptote (y = 0). The second represents the second (y = x). We just subtract one side from the other to turn the equation into a root (i.e. y = x, y – x = 0).

Study the equation
image Plug this equation into Wolfram Alpha and it tells you that it is a pair of intersecting lines. We already knew that. We need to pull back from those two lines and see what happens. Let’s change the equation to this:

  • y * (y – x) = 9

Now Wolfram Alpha tells us that it is a hyperbola. We can visually verify that it approaches zero on the left, and it approaches a 1-to-1 slope on the right.

We can also see that the equation crosses the y axis at 3. This is about where we “switch modes” from a big object to a little one. And finally, we can see the solution for y:

  • y = 1/2 (x-sqrt(x^2+36))

With a little work on the whiteboard, we can confirm that the numbers 3 and 36 are related to the arbitrarily chosen constant 9. The y intercept (3) is the square root, and the constant (36) is quadruple. With this knowledge, we can adjust the equation to “switch modes” at any screen size.

Complete the algorithm
With a little more help from Steven Wolfram, we can find the inverse of this equation. With that, we turn this equation into an algorithm for determining the new size of an object:

  • Screen size = actual size * zoom factor
  • Starting x = (screen size^2 – small object^2) / screen size
  • New x = starting x + ticks * pixels per tick
  • New screen size = 1/2 (new x-sqrt(new x^2 + small object * 4))
  • New actual size = new screen size / zoom factor

And with that we have one algorithm that operates one way on small objects, and another way on large objects. And it allows the user to fine tune by zooming in.

My partner’s comment
I walked through this code with my partner, and explained how it solved three problems at once. His reaction was, “You used math where I would have used an if statement.” I think that was the most telling result of the whole exercise.

When we write code using discrete concepts like conditions, we apply brute force. We decide exactly where the solution changes from one mode to another. We force a corner into the solution. A singularity at which the behavior of the system changes violently. Bugs gather at such singularities. And those corners poke the user in the eye, even if he can’t put his finger on them.

But when we find one simple, continuous, elegant solution to many problems, we allow that solution to take its own form. It emerges naturally from the problem space itself. The benefit is not simply more beautiful code. It is also fewer bugs, and a more pleasant user experience. So when faced with a multitude of problems, put them all together and see if a single solution emerges.

Hands-on MVVM 4b: Communicate through the data model

Friday, May 14th, 2010

I presented this material at Dallas XAML on May 4, 2010. Please download the demo code and follow along. This post takes us the rest of the way the project called “Step4”.

When we left the project in part 4, we had injected a layer between the model and the view. In the process, we broke updates. Now let’s fix them.

Add INotifyPropertyChanged to the view model
Updates stopped working because we are now data binding to the view model. As of yet, the view model does not implement INotifyPropertyChanged. As I mentioned in part 2, there are really only two reasons to ever fire PropertyChanged:

  1. Something other than the view changes the property, or
  2. The property depends upon another property.

Neither WPF nor Silverlight need you to fire PropertyChanged for a property that the view itself is changing. The view already knows that it has changed. It’s the one that changed it!

The updates that failed are all related to dependent properties. DisplayAs depends upon first name, last name, and email. Title depends upon DisplayAs. We moved both of these properties into the view model. So the view model needs to know when these properties change.

Possible solution: interception
Since the view model wraps the data model, it is possible to intercept changes on their way to the data model. The PersonViewModel understands what Title depends upon, and it intercepts all of those properties. It can fire the appropriate PropertyChanged events.

public string FirstName
{
    get { return _person.FirstName; }
    set { _person.FirstName = value; FirePropertyChanged("Title"); }
}

public string LastName
{
    get { return _person.LastName; }
    set { _person.LastName = value; FirePropertyChanged("Title"); }
}

public string Email
{
    get { return _person.Email; }
    set { _person.Email = value; FirePropertyChanged("Title"); }
}

public string Phone
{
    get { return _person.Phone; }
    set { _person.Phone = value; }
}

public DisplayStrategyViewModel DisplayAs
{
    get { return new DisplayStrategyViewModel(_person, _person.DisplayAs); }
    set { _person.DisplayAs = value.DisplayStrategy; FirePropertyChanged("Title"); }
}

When the user changes any of the properties that Title depends upon, the view model fires PropertyChanged for the Title. Title does not depend upon Phone, so that one doesn’t fire. The view model is keeping track of dependencies.

But what about the DisplayStrategyViewModel? It doesn’t intercept the properties that it depends upon. It needs to be notified when FirstName, LastName, or Email is changed. That means that PersonViewModel would have to send these notifications to DisplayStrategyViewModel. That’s too much coupling between the two. Let’s find a different solution.

Better solution: indirect notification

The view models already have something in common. They both know about the Person data model. Let’s allow them to communicate with each other through the data model.

When the PersonDataModel changes one of the properties on the Person object, the DisplayStrategyViewModel should hear about it. It needs to know about those property changes. We have, conveniently enough, a mechanism for listening to property changed events. Although INotifyPropertyChanged is intended for data binding, you can use it for your own internal notification as well.

Person already implements INotifyPropertyChanged. But it used to fire property changed events for dependent properties. Now we want to know about changes to the properties themselves. Let’s add those notifications.

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; FirePropertyChanged("FirstName"); }
    }

    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; FirePropertyChanged("LastName"); }
    }

    public string Email
    {
        get { return _email; }
        set { _email = value; FirePropertyChanged("Email"); }
    }

    public string Phone
    {
        get { return _phone; }
        set { _phone = value; FirePropertyChanged("Phone"); }
    }
}

Person no longer keeps track of dependent properties. That’s the view model’s job. Now it’s firing PropertyChanged events so that the view models can collaborate with each other. To close the loop, DisplayStrategyViewModel needs to listen.

public class DisplayStrategyViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public DisplayStrategyViewModel(
        Person person,
        DisplayStrategy displayStrategy)
    {
        _person = person;
        _displayStrategy = displayStrategy;

        _person.PropertyChanged += PersonPropertyChanged;
    }

    private void PersonPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "FirstName" || e.PropertyName == "LastName" || e.PropertyName == "Email")
            FirePropertyChanged("Display");
    }
}

Now when the PersonViewModel changes one of the properties that DisplayStrategyViewModel depends upon, it can notify the view.

Best solution: automatic dependency management

Wouldn’t it be better if you didn’t have to write all of that dependency management code in the view model? You don’t, if you use Update Controls. But this isn’t an Update Controls presentation, so back to doing it manually.

Finish it out

To finish the transition from the interception solution to the notification solution, we remove the interceptors from the PersonViewModel. Instead, that view model also listens to changes.

public class PersonViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private Person _person;

    public PersonViewModel(Person person)
    {
        _person = person;

        _person.PropertyChanged += PersonPropertyChanged;
    }

    void PersonPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        FirePropertyChanged("Title");
    }
}

Now all of the view models listen to changes in the data model. If anything changes the data model, the view model will notify the view of changes to dependent properties. It’s like a publish-subscribe mechanism, but we’re using the data model itself. The data model has become the conduit for messages.

Next time, we’ll upgrade our application to manage a collection of people. In the process, we will dispel some of the myths about ObservableCollection.

Collapse a WPF or Silverlight panel on null

Thursday, May 13th, 2010

Add this style to app.xaml.

<Style x:Key="CollapseOnNull">
    <Style.Triggers>
        <DataTrigger Binding="{Binding}" Value="{x:Null}">
            <Setter Property="FrameworkElement.Visibility" Value="Collapsed"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

Set the style on a panel that is data bound to a selected item (ala Navigation Model).

<DockPanel DataContext="{Binding OpenProject}" Style="{StaticResource CollapseOnNull}">

Now the panel collapses when nothing is selected.

Convention-based view model registration

Sunday, May 9th, 2010

When you create a ListBox or ItemsControl, you usually specify an ItemTemplate to render each of the items. You can do so directly in the ItemsControl itself.

<ListBox ItemsSource="{Binding Projects}" SelectedItem="{Binding SelectedProject}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Or you can identify a resource by name.

<UserControl.Resources>
    <DataTemplate x:Key="ProjectItemTemplate">
        <TextBlock Text="{Binding Name}"/>
    </DataTemplate>
</UserControl.Resources>

<ListBox
    ItemsSource="{Binding Projects}"
    SelectedItem="{Binding SelectedProject}"
    ItemTemplate="{StaticResource ProjectItemTemplate}"/>

Either of these methods causes every item to be rendered in the same way. But what if different kinds of items are represented with different views? If you want each item to be rendered according to its type, you can add all of the data templates to the resource dictionary. The list will select the data template based on the item type.

<UserControl.Resources>
    <DataTemplate DataType="{x:Type projects:SoftwareProject}">
        <StackPanel>
            <TextBlock Text="{Binding Name}"/>
            <TextBlock Text="{Binding LinesOfCode}"/>
        </StackPanel>
    </DataTemplate>
    <DataTemplate DataType="{x:Type projects:HardwareProject}">
        <StackPanel>
            <TextBlock Text="{Binding Name}"/>
            <TextBlock Text="{Binding ServerCount}"/>
        </StackPanel>
    </DataTemplate>
</UserControl.Resources>

<ListBox
    ItemsSource="{Binding Projects}"
    SelectedItem="{Binding SelectedProject}"/>

Convention over configuration

You can explicitly add data templates to a resource dictionary if you have only a few closely related types to choose from. But explicit configuration becomes tedious if this set of types changes frequently, if there are many of them, or if they are located in different namespaces. In some cases, it is easier to adopt a convention-based approach.

I started the WPF LOB project on Codeplex to experiment with patterns for line-of-business applications in WPF. One of those patterns is switching among views within the same window. The project defines a base class for view models that represent panes within the window. It uses convention over configuration to associate those view models with their views.

The main form looks for all classes that inherit from Pane and end with the words “ViewModel”. By convention, the view model will be located in a namespace called “ViewModel”. The associated view will be a user control located in a namespace called “View”, and ending with the word “View”. The main form applies that convention to locate the view, and adds a data template to the resource dictionary.

public MainWindow()
{
    InitializeComponent();
    RegisterAllPanes();
}

private void RegisterAllPanes()
{
    // Find all pane view model types in the assembly.
    Assembly assembly = Assembly.GetExecutingAssembly();
    foreach (Type viewModelType in assembly.GetTypes())
    {
        if (typeof(Pane).IsAssignableFrom(viewModelType) && viewModelType.Name.EndsWith("ViewModel"))
        {
            string viewTypeName = viewModelType.FullName.Replace("ViewModel", "View");
            Type viewType = assembly.GetType(viewTypeName);
            if (viewType != null)
                RegisterDataTemplate(viewModelType, viewType);
        }
    }
}

private void RegisterDataTemplate(Type viewModelType, Type viewType)
{
    DataTemplate dataTemplate = new DataTemplate(viewModelType)
    {
        VisualTree = new FrameworkElementFactory(viewType)
    };
    Resources.Add(dataTemplate.DataTemplateKey, dataTemplate);
}

Caliburn

Rob Eisenberg created an MVVM framework called Calliburn that relies heavily on convention over configuration. His framework goes so far as to data bind controls to properties based on convention, rather than configuring each using the “{Binding}” markup extension. Watch his presentation from Mix10. If you would like to develop applications within the realm of his opinion, I recommend investing the time in learning Caliburn. But even if you don’t, you can still use simple techniques like the one above to take advantage of convention over configuration when it makes the most sense.

Hands-on MVVM 4: the View Model layer

Friday, May 7th, 2010

I presented this material at Dallas XAML on May 4, 2010. Please download the demo code and follow along. This post takes us half way the project called “Step4”. The next one will take us the rest of the way, but then the numbers will be out of sync.

In part 3, we added a “Display As” feature to the system. In doing so, the data model started getting messy. This time, we’ll pull those view-specific features out of the data model.

The data model has a job to do. It evaluates domain logic. That’s already enough for a single class. We don’t want to further burden it with managing a view. Robert C. Martin tells us of the Single Responsibility Principle. A class should have only one reason to change. If you’re changing the data model, it’s because you are modifying the domain. You shouldn’t also change it when modifying the behavior of a view. So let’s move that behavior out of the data model. The place it goes is the View Model. We data bind to the view model rather than to the data model.

View-specific properties
The Title property of the Person class exists to serve the view. It’s not the title of a person; it’s the title of a window that displays a person. This is the first to go.

public class PersonViewModel
{
    private Person _person;

    public PersonViewModel(Person person)
    {
        _person = person;
    }

    public string Title
    {
        get
        {
            return "Person - " + _person.DisplayUsingStrategy(_person.DisplayAs);
        }
    }
}

The Person View Model takes a reference to a Person. It uses the Person to provide the desired behavior.

Pass-through properties

The view displays text boxes where the user can edit the properties of a person directly. Since the view is no longer bound directly to the data model, we have to pass these properties through the view model.

public class PersonViewModel
{
    private Person _person;

    public PersonViewModel(Person person)
    {
        _person = person;
    }

    public string FirstName
    {
        get { return _person.FirstName; }
        set { _person.FirstName = value; }
    }

    public string LastName
    {
        get { return _person.LastName; }
        set { _person.LastName = value; }
    }

    public string Email
    {
        get { return _person.Email; }
        set { _person.Email = value; }
    }

    public string Phone
    {
        get { return _person.Phone; }
        set { _person.Phone = value; }
    }

    public string Title
    {
        get
        {
            return "Person - " + _person.DisplayUsingStrategy(_person.DisplayAs);
        }
    }
}

No data is stored in the view model itself. It all passes through to the data model.

One view model per DataContext

The “Display As” combo box has an ItemsSource that is data bound to a collection. Each item in this collection is the DataContext of one combo box item. Before it was a string. Now we’ll make it a view model of its own.

public class DisplayStrategyViewModel
{
    private Person _person;
    private DisplayStrategy _displayStrategy;

    public DisplayStrategyViewModel(Person person, DisplayStrategy displayStrategy)
    {
        _person = person;
        _displayStrategy = displayStrategy;
    }

    public string Display
    {
        get { return _person.DisplayUsingStrategy(_displayStrategy); }
    }
}

Again, this view model passes its behavior through to the Person object. But now it displays that person according to a given display strategy. We use a DataTemplate to show that property in the combo box.

<ComboBox ItemsSource="{Binding DisplayAsOptions}" SelectedItem="{Binding DisplayAs}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Display}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

And now we need to generate these view models.

Project through a factory

The simplest way to generate a collection of view models is to use linq to project a collection of data objects through a view model constructor. In this case, we are listing all of the display options, so we project the values of the DisplayStrategy enumeration. We add this property to the Person View Model.

public IEnumerable<DisplayStrategyViewModel> DisplayAsOptions
{
    get
    {
        return Enum.GetValues(typeof(DisplayStrategy))
            .OfType<DisplayStrategy>()
            .Select(displayStrategy =>
                new DisplayStrategyViewModel(_person, displayStrategy));
    }
}

From the list of DisplayStrategy values, we produce a list of Display Strategy View Models that render the person using different options.

ItemsSource/SelectedItem duality

Finally, the user needs to select one of the display strategies from the combo box. The SelectedItem property provides this behavior. It is the dual of the ItemsSource property: its type must be the same as the IEnumerable generic parameter.

public DisplayStrategyViewModel DisplayAs
{
    get { return new DisplayStrategyViewModel(_person, _person.DisplayAs); }
    set { _person.DisplayAs = value.DisplayStrategy; }
}

This property wraps the DisplayAs selection in a view model so that it agrees with the type of the list.

Equals and GetHashCode

If you were to run the code now, you would see that the window comes up initially blank. But when you select a “Display As” setting, it appears correctly. The problem is that the view cannot find the SelectedItem in the ItemsSource collection. For each property, we created a new Display Strategy View Model. These are two different instances of similar objects. To tell the view that they are indeed the same, we need to implement Equals and GetHashCode in DisplayStrategyViewModel.

public override bool Equals(object obj)
{
    if (obj == this)
        return true;
    DisplayStrategyViewModel that = obj as DisplayStrategyViewModel;
    if (that == null)
        return false;
    return _displayStrategy == that._displayStrategy;
}

public override int GetHashCode()
{
    return _displayStrategy.GetHashCode();
}

Now the view recognizes that they are the same, so the window appears correctly. You must always implement Equals and GetHashCode when you create an ItemsSource/SelectedItem dual.

We have successfully moved the view-specific behavior out of the data model and into a view model. We pass all of the properties that are data-bound to the view through to the data model. By projecting related objects through a constructor, we can keep a view model layer in between the view and the data model at all times.

The application works now, but there are a few places that no longer update. That’s because we didn’t implement INotifyPropertyChanged on the view model to tell the view about dependent properties. In part 4, we’ll add INotifyPropertyChanged to get that behavior back.

Hands-on MVVM 3: ItemsSource and SelectedItem

Wednesday, May 5th, 2010

display_asI presented this material at Dallas XAML last night (May 4, 2010). If you attended, I hope you had as much fun as I did. If not, just download the demo code and follow along.

In part 2, we saw why we need to fire PropertyChanged events. It’s not for the benefit of the properties that the view is changing directly. It’s for the dependent properties.

Display strategy
Now we want to add another new feature to the system. We want to let the user choose how a person is displayed. They can choose from among three display strategies: last-first, first-last, or email.

The chosen display strategy is stored with the person. The user can choose to display one person using their formal name (last-first), and another using their informal name (first-last). It is not a global setting.

The user selects a display strategy from a combo box. We add this to the person view.

<ComboBox Grid.Row="4" Grid.Column="1" x:Name="displayAs"
    ItemsSource="{Binding DisplayAsOptions}" SelectedItem="{Binding DisplayAs}"/>

This combo box needs to show a list of options. We’ll generate these options by applying different display strategies to the person.

public IEnumerable<string> DisplayAsOptions
{
    get
    {
        return Enum.GetValues(typeof(DisplayStrategy))
            .OfType<DisplayStrategy>()
            .Select(displayStrategy => DisplayUsingStrategy(displayStrategy));
    }
}

public string DisplayUsingStrategy(DisplayStrategy displayStrategy)
{
    if (displayStrategy == DisplayStrategy.LastFirst)
        return string.Format("{0}, {1}", _lastName, _firstName);
    else if (displayStrategy == DisplayStrategy.FirstLast)
        return string.Format("{0} {1}", _firstName, _lastName);
    else
        return _email;
}

The DisplayAsOptions property gets all values of the DisplayStrategy enumeration and projects that set through the DisplayUsingStrategy method. The DisplayUsingStrategy method formats the person for the given strategy. The result is a collection of strings.

When the user selects one of those strings, they will set the DisplayAs property. Since DisplayAsOptions is an IEnumerable<string>, DisplayAs has to be a string.

public string DisplayAs
{
    get { return DisplayUsingStrategy(_displayAs); }
    set
    {
        _displayAs = (DisplayStrategy)DisplayAsOptions
            .ToList()
            .FindIndex(option => option == value);
    }
}

The DisplayAs getter just applies the current display strategy for the person. The setter, however, has to find the selected string in the list of options. The index of this string corresponds to the ordinal value of the enumeration that generated it.

The important thing here is the duality of the DisplayAsOptions and DisplayAs properties. DisplayAsOptions has type IEnumerable<string>. DisplayAs has type string. These types must agree, because one is data bound to ItemsSource and the other to SelectedItem.

Update the title

Now that the user can select the display strategy for the person, we should use that display strategy in the title of the window. We make the necessary change to the Title property.

public string Title
{
    get
    {
        return "Person - " + DisplayUsingStrategy(_displayAs);
    }
}

When we run the app, it doesn’t look like it’s working. When we change the display strategy, the title doesn’t update. Did we forget to compile? No. We just forgot to tell XAML that the title depends upon DisplayAs.

public string DisplayAs
{
    get { return DisplayUsingStrategy(_displayAs); }
    set
    {
        _displayAs = (DisplayStrategy)DisplayAsOptions
            .ToList()
            .FindIndex(option => option == value);
        FirePropertyChanged("Title");
    }
}

Now the title updates when we change the display strategy.

Messy model

Take a step back and look at the model that we’ve created. The Person class has the following properties.

  • FirstName
  • LastName
  • Email
  • Phone
  • DisplayAs
  • DisplayAsOptions
  • Title

How many of these are actually the responsibility of the model? How many are just there to satisfy the view? As we’ve added features to the application, we’ve allowed the view’s concerns to creep into the data model. If we continue in this vein, the data model will get very messy.

In part 4, we’ll pull the view’s concerns out of the data model. That’s the first time in this series that we’ll really see the MVVM pattern.

Hands-on MVVM 2: Dependent properties

Tuesday, May 4th, 2010

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

In part 1 we created a model and a view. Now we start adding features and seeing how our code changes.

Window title
The first feature to add is to display the name of the person in the title bar of the window. The view is a user control, but it’s hosted inside of a window. We already set the DataContext of the window so that it would be inherited by the user control. So we can just data bind the title.

<Window x:Class="Step2.PersonWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:view="clr-namespace:Step2.View"
    Title="{Binding Title}" Height="300" Width="468">
    <view:PersonUserControl/>
</Window>

Bound property

The data context that we set was the Person model object. So we have to add this Title property to the 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; }
    }

    public string Title
    {
        get
        {
            return string.Format("Person - {0}, {1}", _lastName, _firstName);
        }
    }
}

Run the program and you’ll see that the title properly displays the person’s name. It looks like everything is working. But change the name and see what happens.

change_name

The title doesn’t update when the name changes. That’s because the view doesn’t know that the title depends upon the name. Unless you have a system that automatically discovers dependencies (not discussed in this series), you have to notify the view.

As you can see, INotifyPropertyChanged is not strictly necessary for data binding to work. The view worked just fine up until now. The properties were not notifying the view when they themselves were changing. That’s because it was the view that was changing them. The view already knows. You only really need INotifyPropertyChanged to notify the view when:

  1. Something other than the view changes the property, or
  2. The property depends upon another property.

Dependent property

In this case, the Title property depends upon the FirstName and LastName properties. So we notify the view that Title has changed when one of those properties change.

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _firstName;
    private string _lastName;
    private string _email;
    private string _phone;

    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; FirePropertyChanged("Title"); }
    }

    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; FirePropertyChanged("Title"); }
    }

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

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

    public string Title
    {
        get
        {
            return string.Format("Person - {0}, {1}", _lastName, _firstName);
        }
    }

    private void FirePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

And now the title updates when you change the name.

We are starting to see the need for a view model. The Title property has nothing to do with our data model. But we’ll let that slide for now.

Today we saw what problem INotifyPropertyChanged solves, and we wrote the simplest thing that works. This is not the best thing, nor is it the right thing. We are watching the code evolve to see why we need MVVM.

Next time we will add another feature to the system and see how the code responds to another change. Stay tuned.

Hands-on MVVM 1: Model and View

Monday, May 3rd, 2010

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.