Blogs

Custom change listeners

A user asked.

When I use a viewmodel as a datacontext everything just works. Now I want to add a listener to the viewmodel of my own design, but am stumped.  Do you have any suggestions? How do I hook up custom change listeners?

It all depends upon what you want to do with the notification. If you want to use that notification to update something else, I’d recommend using a Dependent instead of an event.

Updating a dependent

Where Independent has OnGet() and OnSet(), Dependent has only OnGet(). You can't directly set a dependent field. It's value is determined by an update method. You pass the update method to the constructor.

Here is an example dependent field.

private class PersonViewModel
{
    private Person _person;

    private string _fullName;
    private Dependent _depFullName;

    public PersonViewModel(Person person)
    {
        _person = person;
        _depFullName = new Dependent(UpdateFullName);
    }

    public string FullName
    {
        get { _depFullName.OnGet(); return _fullName; }
    }

    private void UpdateFullName()
    {
        _fullName = string.Format("{0}, {1}", _person.LastName, _person.FirstName);
    }
}

The UpdateFullName method is called only when the full name is out-of-date. If you access FullName again without changing the person’s name, the method is not called a second time.

The advantage of Dependent over events is dependency management. If you used events, you would have to know which events to subscribe to. Dependent, on the other hand, discovers its dependencies. This is why you use Update Controls instead of INotifyPropertyChanged in the first place.

Firing an event

But suppose that you need to notify something else for a different reason. Maybe you need to send a message to an external system. In this case, you can hook the Invalidated event of the Dependent. Add the hook to the constructor, like this:

public PersonViewModel(Person person)
{
    _person = person;
    _depFullName = new Dependent(UpdateFullName);
    _depFullName.Invalidated += delegate
    {
        Dispatcher.CurrentDispatcher.BeginInvoke(() =>
        {
            if (FullNameChanged != null)
                FullNameChanged();
        });
    };
}

The Invalidated event is fired whenever the Dependent becomes out-of-date. One of the Independent fields upon which it depends has just changed.

It is very important that your Invalidated handler does not try to synchronously get the updated value. The Independent field may not have its new value, yet. And even if it did, there may be additional changes coming. That is why the above example fires the FullNameChanged event asynchronously.

By the way, the code above is exactly how UpdateControls.XAML implements INotifyPropertyChanged.

Remember that Update Controls replaces imperative events with declarative dependency discovery. If you can avoid firing events, your application will be less brittle. But if you really need events, you can get them.

Wrap it yourself

Occasionally circumstances will prevent you from using ForView.Wrap() to wrap your view model. For example, prior to version 2009.3.1127, Telerik’s RadGridView for Silverlight did not support DependencyProperties: the DataContext of the rows had to implement INotifyPropertyChanged. Download the source code and follow along. The Silverlight DataGrid will be playing the part of the Telerik RadGridView control, even though DataGrid can bind to DependencyProperties just fine.

You can pick-and-choose which view models can be wrapped automatically and which can be wrapped manually. If your View Model implements INotifyPropertyChanged, then ForView.Wrap() will let it pass through. So we only need to implement INotifyPropertyChanged on the view model that represents a row in the grid.

public class PersonViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
}

There are 4 steps to implementing INotifyPropertyChanged on your own with Update Controls:

  1. Create a Dependent for each property.
  2. Initialize each Dependent with a lambda that calculates the value and assigns it to a field.
  3. In the getter of each property, call OnGet on the Dependent, then return the field.
  4. When the Invalidated event of each Dependent is fired, dispatch a call to the PropertyChanged event.

First we create a Dependent for each property. A Dependent is a sentry that guards the property and determines when it needs to be updated.

public class PersonViewModel : INotifyPropertyChanged
{
    private Person _person;
    private Dependent _depFirst;

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

    public event PropertyChangedEventHandler PropertyChanged;
}

Second, we initialize each Dependent with a lambda. When the Dependent needs to be updated, it will invoke this lambda. The lambda should calculate the dependent property and store it in a field.

public class PersonViewModel : INotifyPropertyChanged
{
    private Person _person;
    private Dependent _depFirst;
    private string _first;

    public PersonViewModel(Person person)
    {
        _person = person;
        _depFirst = new Dependent(() => _first = _person.First);
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Third, we call OnGet on the Dependent. OnGet will determine whether the Dependent is out-of-date. If so, it will invoke the lambda. The results of the calculation will be stored in a field. Return this field from the property getter.

public class PersonViewModel : INotifyPropertyChanged
{
    private Person _person;
    private Dependent _depFirst;
    private string _first;

    public PersonViewModel(Person person)
    {
        _person = person;
        _depFirst = new Dependent(() => _first = _person.First);
    }

    public string First
    {
        get { _depFirst.OnGet(); return _first; }
        set { _person.First = value; }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Fourth, we use the Invalidated event of each Dependent to fire PropertyChanged. Invalidated is fired when the Dependent goes out-of-date. This occurs when any Independent property that the calculation reads is changed. The trick is that the PropertyChanged event needs to be dispatched, so that it will be fired after that change has completed. Otherwise the system will get stuck in an infinite update loop.

public class PersonViewModel : INotifyPropertyChanged
{
    private Person _person;
    private Dependent _depFirst;
    private string _first;

    public PersonViewModel(Person person)
    {
        _person = person;
        _depFirst = new Dependent(() => _first = _person.First);
        _depFirst.Invalidated += () => FirePropertyChanged("First");
    }

    public string First
    {
        get { _depFirst.OnGet(); return _first; }
        set { _person.First = value; }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void FirePropertyChanged(string propertyName)
    {
        App.Current.RootVisual.Dispatcher.BeginInvoke(() =>
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        });
    }
}

Hopefully you can let ForView.Wrap() handle data binding for you. But in those situations where you cannot, you could always wrap it yourself.

Awesome application

I presented Update Controls in WPF, Silverlight, and Winforms online for a bunch of folks not at PDC. You can download the source code and watch the recording to follow along.

The most awesome app ever
The most awesome app ever is Excel. Actually, it’s Excel’s great grandfather VisiCalc. With these apps you express the relationship among parts of your data. The spreadsheet figures out when to recalculate and keep things up to date.

You can demonstrate the View Model pattern in Excel. Put your name in C1. That’s the data model. Then enter the formula “=C1” into B1. That’s the view model. It gets its data from the data model. It doesn’t store that data, it just interprets it for the benefit of a specific view. Finally, put the formula “=B1” into A1. This is your view. It binds to properties of your data model. It can’t do complex logic. That’s the View Model’s job.

I want to write my application the same way that I construct a spreadsheet. It should just know what depends upon what, and keep things up to date. That’s what I demonstrate with Update Controls.

Don’t copy data
The View Model does not make a copy of your data. It delegates to the Data Model. If data is stored in two places, it might get out of sync. If it’s stored in only one place, then there is no chance of inconsistency.

The View Model in this example does not have any fields, other than the references that are assigned during construction. If you are storing state in your data model, you are probably making a mistake. If that state is a copy of what’s in the Data Model, or it can be calculated from the Data Model, then delegate. If not consider moving it to a navigation model.

Navigation model
Your application exists for one purpose: to manage information in a specific problem domain. That is what goes into the Data Model. Everything else is there to help the user navigate through that information. That goes into the Navigation Model.

The Navigation Model keeps track of selected items. The selected item of a ListBox is bound to a property on the View Model. That property just delegates to the Navigation Model. Putting the user selection into the Navigation Model instead of directly binding controls to one another allows you to programmatically change the selection. All you do is change the property in the Navigation Model.

The Navigation Model also keeps track of search parameters. A TextBox is bound to a Filter property, which delegates to the Navigation Model. A where clause in the linq query in the View Model compares items to this Filter. Since the linq query references the Filter property, the list is dependent upon it. Changing the Filter updates the list.

Rapidly added features
Update Controls discovers dependencies for you. You don’t have to manage dependencies on your own. When you do your own dependency management, you have to touch old code to add a new feature. But when the system manages dependencies, you can add new code and the old code will continue to behave as expected. All you have to do is:

  • Store domain data in the Data Model.
  • Store user selection and navigation in the Navigation Model.
  • Delegate from the View Model to either the Data or the Navigation Model: don’t store state in the View Model.
  • Use Independent on all Data and Navigation Model fields.
  • Use ForView.Wrap() on all DataContexts that you set through code.

VM Workshop

Craig Shoemaker has created a reference application for the MVVM pattern called VM Workshop. The idea behind a reference application is to have one application written with different technologies so that they can be compared with one another. Each incarnation of the reference application is called a reference implementation. Craig has created six such reference implementations to demonstrate different UI technologies: Silverlight, WPF, Webforms, Winforms, ASP.NET MVC, and Ajax.

To support this impressive effort, I humbly contribute the Update Controls reference implementations. Let me start with the WPF implementation. Download the source and follow along.

Independent sentries
I started with Craig’s WPF reference implementation, then modified code as necessary to demonstrate the Update Controls way. The first change was to add Independent sentries to the data model:

public class Product 
{ 
    /* Primary key */ 
    public int ProductId { get; set; } 

    /* Data members */ 
    private string _title; 
    private string _description; 
    private int _quantityOnHand; 
    private double _price; 
    private DateTime _releaseDate; 

    #region Independent properties 
    // Generated by Update Controls -------------------------------- 
    private Independent _indTitle = new Independent(); 
    private Independent _indDescription = new Independent(); 
    private Independent _indQuantityOnHand = new Independent(); 
    private Independent _indPrice = new Independent(); 
    private Independent _indReleaseDate = new Independent(); 

    public string Title 
    { 
        get { _indTitle.OnGet(); return _title; } 
        set { _indTitle.OnSet(); _title = value; } 
    } 

    public string Description 
    { 
        get { _indDescription.OnGet(); return _description; } 
        set { _indDescription.OnSet(); _description = value; } 
    } 

    public int QuantityOnHand 
    { 
        get { _indQuantityOnHand.OnGet(); return _quantityOnHand; } 
        set { _indQuantityOnHand.OnSet(); _quantityOnHand = value; } 
    } 

    public double Price 
    { 
        get { _indPrice.OnGet(); return _price; } 
        set { _indPrice.OnSet(); _price = value; } 
    } 

    public DateTime ReleaseDate 
    { 
        get { _indReleaseDate.OnGet(); return _releaseDate; } 
        set { _indReleaseDate.OnSet(); _releaseDate = value; } 
    } 
    // End generated code -------------------------------- 
    #endregion 

    /* Audit members */ 
    public DateTime CreatedOn { get; set; } 
    public string CreatedBy { get; set; } 
    public DateTime ModifiedOn { get; set; } 
    public string ModifiedBy { get; set; } 
    public bool IsDeleted { get; set; } 
}

Only the properties that the user can change are guarded with Independent sentries. The ID and the audit members are not under the user’s control.

Don’t store state in the View Model

Next the View Model got a complete overhaul. Craig’s View Model stores state, which he keeps in sync with the data model through well-orchestrated code. The Update Controls way, however, is to store only a reference to the data model. When the View Model needs data, it asks for it. That way there is no synchronization to orchestrate.

Take, for example, the way that Craig orchestrates the products list:

public class DemoViewModel : INotifyPropertyChanged 
{ 
    // Events 
    public event PropertyChangedEventHandler PropertyChanged; 

    // Private fields 
    private IList<ProductListView> _products; 
    private IProductRepository _repository; 

    // Public properties 
    public IList<ProductListView> Products 
    { 
        get  
        { 
            if (this._products == null) 
            { 
                this._products = this.GetProducts(); 
            } 
            return this._products;  
        } 
        set 
        { 
            if (this._products != value) 
            { 
                this._products = value; 
                this.RaisePropertyChangedEvent("Products"); 
            } 
        } 
    } 

    // Constructor 
    public DemoViewModel(IProductRepository repository) 
    { 
        this._repository = repository; 
    } 

    // Utilities 
    private IList<ProductListView> GetProducts() 
    { 
        var products = this._repository.GetAll(); 
        return Mapper.Map<IList<Product>, IList<ProductListView>>(products); 
    } 

    protected virtual void RaisePropertyChangedEvent(params string[] propertyNames) 
    { 
        if (this.PropertyChanged != null) 
        { 
            foreach (string name in propertyNames) 
            { 
                this.PropertyChanged(this, new PropertyChangedEventArgs(name)); 
            } 
        } 
    } 
}

He keeps a list of products in the View Model, which he loads from the repository and writes back to the repository at just the right times. He uses Automapper to copy the state of a Product into a ProductListView. When the Product changes, he has to copy that state again (a feature which he has not yet added at the time of writing).

Compare this to the Update Controls way:

public class DemoViewModel 
{ 
    // Private fields 
    private IProductRepository _repository; 

    // Public properties 
    public IEnumerable<ProductViewModel> Products 
    { 
        get  
        { 
            return _repository.GetAll() 
                .Select(p => new ProductViewModel(p)); 
        } 
    } 

    // Constructor 
    public DemoViewModel(IProductRepository repository) 
    { 
        this._repository = repository; 
    } 
}

When the View Model needs the list of products, it just goes to the repository and gets it. And it doesn’t copy each product into another data structure. It just wraps each product in a View Model of its own. These Product View Models similarly hold no state. They just delegate to the Product data model.

public class ProductViewModel 
{ 
    private Product _product; 

    public ProductViewModel(Product product) 
    { 
        _product = product; 
    } 

    public string Title 
    { 
        get { return _product.Title; } 
        set { _product.Title = value; } 
    } 

    public string Description 
    { 
        get { return _product.Description; } 
        set { _product.Description = value; } 
    } 

    public int QuantityOnHand 
    { 
        get { return _product.QuantityOnHand; } 
        set { _product.QuantityOnHand = value; } 
    } 

    public double Price 
    { 
        get { return _product.Price; } 
        set { _product.Price = value; } 
    } 

    public DateTime ReleaseDate 
    { 
        get { return _product.ReleaseDate; } 
        set { _product.ReleaseDate = value; } 
    } 

    public Product Product 
    { 
        get { return _product; } 
    } 
}

The advantage of this method is that there is only one source of data: the data model. There are no intermediate copies to accidentally get out of sync. The purpose of the View Model is not to cache intermediate data. It is there to transform the data for consumption by the view.

Add a Navigation Model

Craig’s View Model has additional state to keep track of user navigation. He stores the selected product, and provides a method for use in code behind to access it.

public class DemoViewModel : INotifyPropertyChanged 
{  
    // Private fields  
    private ProductEditView _selectedProduct;  

    // Public properties  
    public ProductEditView SelectedProduct 
    { 
        get { return this._selectedProduct; } 
        set 
        { 
            if (this._selectedProduct != value) 
            { 
                this._selectedProduct = value; 
                this.RaisePropertyChangedEvent("SelectedProduct"); 
            } 
        } 
    }  

    // Public API methods  
    public void GetSelectedProduct(int productId) 
    { 
        Product product = this._repository.GetProductById(productId); 
        this.SelectedProduct = ProductEditView.ToProductEditView(product); 

        this.EditFormVisibility = Visibility.Visible; 
        this.UpdateMessageVisibility = Visibility.Collapsed; 
    } 
}

The Update Controls way, on the other hand, is to move this state into a Navigation Model. Both the data grid and the edit panel data bind to the same property, so no code behind is required.

public class DemoViewModel 
{ 
    // Private fields 
    private DemoNavigationModel _navigation = new DemoNavigationModel(); 

    // Public properties 
    public ProductViewModel SelectedProduct 
    { 
        get { return _navigation.SelectedProduct == null ? null : new ProductViewModel(_navigation.SelectedProduct); } 
        set { _navigation.SelectedProduct = value == null ? null : value.Product; } 
    } 
}

The Navigation Model guards this property with Independent sentries, since it is under the user’s control.

public class DemoNavigationModel 
{ 
    private Product _selectedProduct; 

    #region Independent properties 
    // Generated by Update Controls -------------------------------- 
    private Independent _indSelectedProduct = new Independent(); 

    public Product SelectedProduct 
    { 
        get { _indSelectedProduct.OnGet(); return _selectedProduct; } 
        set { _indSelectedProduct.OnSet(); _selectedProduct = value; ProductIsUpdated = false; } 
    } 
    // End generated code -------------------------------- 
    #endregion 
}

Change the view through Styles and DataTriggers

One final change was to the way that visibility is controlled. The edit panel should only be visible when a product is selected, and a message should be displayed when a product is saved. Craig implemented these features by data binding the Visibility property of these controls to a couple of View Model properties:

public class DemoViewModel : INotifyPropertyChanged 
{  
    // Private fields  
    private Visibility _editFormVisibility = Visibility.Collapsed; 
    private Visibility _updateMessageVisibility = Visibility.Collapsed; 

    // Public properties 
    public Visibility EditFormVisibility 
    { 
        get { return this._editFormVisibility; } 
        set 
        { 
            if (this._editFormVisibility != value) 
            { 
                this._editFormVisibility = value; 
                this.RaisePropertyChangedEvent("EditFormVisibility"); 
            } 
        } 
    } 

    public Visibility UpdateMessageVisibility 
    { 
        get { return this._updateMessageVisibility; } 
        set 
        { 
            if (this._updateMessageVisibility != value) 
            { 
                this._updateMessageVisibility = value; 
                this.RaisePropertyChangedEvent("UpdateMessageVisibility"); 
            } 
        } 
    } 
}

He sets these properties within the View Model at the appropriate times to show and hide the controls. He binds the Visibility of the controls directly to these properties.

<Grid x:Name="editGrid" Margin="5" Visibility="{Binding EditFormVisibility}">
</Grid>

An alternative is to use Styles to set properties of controls. A DataTrigger sets the control property based on the value of a View Model property.

<Window.Resources>
    <Style x:Key="ProductGridStyle" TargetType="Grid">
        <Style.Triggers>
            <DataTrigger Binding="{Binding SelectedProduct}" Value="{x:Null}">
                <Setter Property="Visibility" Value="Collapsed"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
    
    <Style x:Key="UpdateMessageStyle" TargetType="TextBlock">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsUpdateMessageVisible}" Value="False">
                <Setter Property="Visibility" Value="Collapsed"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

<Grid x:Name="editGrid" Margin="5" Style="{StaticResource ProductGridStyle}">
</Grid>

<TextBlock Style="{StaticResource UpdateMessageStyle}" Text="Your changes are saved." />

The advantage of this technique is that the View Model does not contain WPF-specific data types. You get better code/markup separation. A designer could even use these triggers to begin animations, and the code would not have to change.

Conclusion

The Update Controls way is quite a bit different from the usual way of implementing the View Model pattern. Update Controls works best when the View Model stores no state, when the user’s selection is moved into a separate Navigation Model, and when DataTriggers control view properties and animations. I owe a dept of gratitude once again to Craig Shoemaker, this time for creating this reference application. By comparing these implementations side-by-side, you can decide whether this style of programming is right for you. If you can get used to the differences, I think you’ll find that the Update Controls code is easier to maintain over the long term.

Do not use ObservableCollection<T>

Update Controls not only implements INotifyPropertyChanged for you, it also makes all of your collections observable. When you use Update Controls, you should not also use ObservableCollection<T>. Use a regular List<T> instead.

Define a property of type List<T> in your data model. Select this property and hit Ctrl+D, G. This code will be generated for you:

public class ContactList
{
    private List<Person> _people = new List<Person>();

    #region Independent properties
    // Generated by Update Controls --------------------------------
    private Independent _indPeople = new Independent();

    public Person NewPerson()
    {
        _indPeople.OnSet();
        Person person = new Person();
        _people.Add(person);
        return person;
    }

    public void DeletePerson(Person person)
    {
        _indPeople.OnSet();
        _people.Remove(person);
    }

    public IEnumerable<Person> People
    {
        get { _indPeople.OnGet(); return _people; }
    }
    // End generated code --------------------------------
    #endregion
}

The Independent property is notified every time the collection changes (NewPerson and DeletePerson). It is also notified every time the collection is modified (the People getter). This is all happening in the data model.

The view model does not store a list. It only has a reference to the data model. Using this reference, it generates a collection of view models on the fly.

public IEnumerable<PersonViewModel> People
{
    get
    {
        return _contactList.People
            .Select(p => PersonViewModel.Wrap(p, _contactList));
    }
}

Where PersonViewModel.Wrap looks like this:

public static PersonViewModel Wrap(Person person, ContactList contactList)
{
    if (person == null)
        return null;
    else
        return new PersonViewModel(person, contactList);
}

This is much easier than managing ObservableCollections. You don't need an intermediate collection. You just wrap your data objects in a view model on the fly.

For more information, please see the example of using Linq to replace ObservableCollection<T>.

Item selection

Unlike a ListBox, a TreeView does not have a SelectedItem. Instead, we have to data bind the IsSelected property of the TreeViewItem to the view model. This can be done globally by defining a style.

<Window.Resources>
    <Style TargetType="TreeViewItem">
        <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
    </Style>
</Window.Resources>

Then we create an IsSelected property on the view model.

public bool IsSelected
{
    get { return _navigation.SelectedSurvey == _survey; }
    set { _navigation.SelectedSurvey = value ? _survey : null; }
}

The TreeViewItem will get this property to determine whether the item appears selected. It will set this property when the user selects an item.

Navigation model

The IsSelected property uses a navigation model to record the selected object. This object records the user's current point-of-view as they navigate the data model. As such, the navigation model contains references to data model objects.

public class GameNavigationModel
{
    private Survey _selectedSurvey;
    private Independent _indSelectedSurvey = new Independent();

    public Survey SelectedSurvey
    {
        get { _indSelectedSurvey.OnGet(); return _selectedSurvey; }
        set { _indSelectedSurvey.OnSet(); _selectedSurvey = value; }
    }
}

Not only is the IsSelected property of the TreeViewItem dependent upon the navigation model, but so are the command buttons. Because of this shared dependency, the command buttons are enabled and disabled as the user selects items in the tree.

public ICommand NewAnswer
{
    get
    {
        return MakeCommand
            .When(() => _navigation.SelectedSurvey != null)
            .Do(() => _navigation.SelectedSurvey.NewAnswer());
    }
}

When the SelectedSurvey is not null, the command button is enabled. When clicked, it adds a new answer to the selected survey.

The navigation model is not just set by the user. It can also be affected by code. For example, when the user creates a new survey, we want that to become the selected one.

public ICommand NewSurvey
{
    get
    {
        return MakeCommand
            .Do(() => _navigation.SelectedSurvey = _game.NewSurvey());
    }
}

The navigation model bridges user selection and application behavior.

Collection of view models

A TreeView -- like a ListBox or any other ItemsControl -- displays a collection of items. Each of the items deserves its own view model. This lets you data bind the contents of the TreeViewItem.

Wrap every item

Produce a collection of view models using Linq or the Select() extension method. The Select() extension method operates on a collection as a whole. It maps every element of the collection into another parallel collection. For example, to wrap every Survey in a SurveyViewModel, you can use this code:

public IEnumerable<SurveyViewModel> Surveys
{
    get
    {
        return _game.Surveys
            .Select(s => SurveyViewModel.Wrap(s, _navigation));
    }
}

The Select method returns a collection containing one view model for every Survey in the data model.

This is equivalent to the "from ... select" Linq syntax:

public IEnumerable<SurveyViewModel> Surveys
{
    get
    {
        return
            from s in _game.Surveys
            select SurveyViewModel.Wrap(s, _navigation);
    }
}

Either way, the method SurveyViewModel.Wrap is called for each Survey in the data model. This method is just a safe way of calling the constructor:

public static Survey
/// <summary>
/// Summary description for Main.
/// </summary>
static void Main(string[] args)
{
  // string variable
  string myString = "myString";

  /* integer 
     variable */
  int myInt = 2;
}
ViewModel Wrap(Survey survey, GameNavigationModel navigation)
{
    if (survey == null)
        return null;
    else
        return new SurveyViewModel(survey, navigation);
}

While the data model contains no nulls, the navigation model may. That's when the safe Wrap method comes in handy.

Retain identity

Update Controls will honor the identity of items in a collection. This is important for retaining selection between updates. If we created a new collection of view models every time, the items that the user had selected before the list changed would no longer be selected afterward.

Update Controls uses the Equals and GetHashCode methods to determine if two items should be treated as identical. These methods of the view model should delegate to the data model.

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

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

These methods should be implemented for every view model that appears in a collection.

Linq

One of the most talked about classes in WPF is ObservableCollection<T>. This is a collection class that notifies listeners whenever something is added or removed. Examples abound of using an ObservableCollection<Person> within the data model of an application. Add a person to the data model, and the view is updated.

But a problem with ObservableCollection<T> appears when you want to filter, map, or otherwise modify the collection on the way to the view. The desired way to accomplish this is to write a Linq query. But that turns the ObservableCollection<T> into an IEnumerable<T>. While the original source collection is observable, the query is not.

Filtered collections are not observable
In the following example, one list box is bound to People, while another is bound to PeopleStartingWithP. The first list is updated, but the second is not.

public class AddressBook
{
    private ObservableCollection<Person> _people = new ObservableCollection<Person>();

    public ObservableCollection<Person> People
    {
        get { return _people; }
    }

    public IEnumerable<Person> PeopleStartingWithP
    {
        get { return _people.Where(p => p.Name.StartsWith("P")); }
    }

    private Random _random = new Random();
    public void NewPerson()
    {
        _people.Add(new Person() { Name = "Person " + _random.Next(100) });
    }
}
<Window x:Class="AddressBook.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <ListBox ItemsSource="{Binding People}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <ListBox Name="FilteredList" ItemsSource="{Binding PeopleStartingWithP}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Button Content="New Person" Click="NewPerson_Click"/>
    </StackPanel>
</Window>
public partial class Window1 : Window
{
    private AddressBook _addressBook = new AddressBook();

    public Window1()
    {
        InitializeComponent();
        DataContext = _addressBook;
    }

    private void NewPerson_Click(object sender, RoutedEventArgs e)
    {
        _addressBook.NewPerson();
    }
}

One commonly used solution to this problem is to programmatically set either the DataContext or ItemsSource to force the list to be updated. This works, but it completely defeats the purpose of using ObservableCollection<T>.

private void NewPerson_Click(object sender, RoutedEventArgs e)
{
    _addressBook.NewPerson();
    FilteredList.ItemsSource = _addressBook.PeopleStartingWithP;
}

Writing code that reaches back into the XAML and sets properties is backwards. This is the way things were done in Winforms. XAML is meant to be declarative. The markup should declare its own ItemsSource, and not rely on code to set it.

Query parameters are not observable
Another problem with this approach occurs when the filter in the Linq query references other data. For example, if we want the user to choose their own first letter, the list should update when a new letter is chosen.

The following code makes this work by implementing INotifyPropertyChanged and firing an event when FirstLetter is changed.

private string _firstLetter = string.Empty;

public string FirstLetter
{
    get { return _firstLetter; }
    set { _firstLetter = value; FirePropertyChanged("PeopleStartingWithFirstLetter"); }
}

public IEnumerable<Person> PeopleStartingWithFirstLetter
{
    get
    {
        if (_firstLetter == string.Empty)
            return _people;
        else
            return _people.Where(p => p.Name.StartsWith(_firstLetter));
    }
}

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

Do you see the problem? I've highlighted it for you. FirstLetter fires an event indicating that PeopleStartingWithFirstLetter has changed. That's not the property that was changed! That's the property that was affected by the change. FirstLetter is independent -- the user can change it. PeopleStartingWithFirstLetter is dependent -- it only responds to change. We've created a reverse dependency where FirstLetter knows about PeopleStartingWithFirstLetter. Again, this code is backwards.

Here's my solution
Update Controls makes data binding through linq queries a breeze. It doesn't require ObservableCollection<T>. It responds to changes to the source collection even if it is a plain-vanilla List<T>. And it even responds when the query parameters are changed. And it does all this without INotifyPropertyChanged or any backwards event registration code. Here's what the class looks like using Update Controls:

public class AddressBook
{
    private List<Person> _people = new List<Person>();
    private string _firstLetter = string.Empty;

    private Independent _indPeople = new Independent();
    private Independent _indFirstLetter = new Independent();

    public IEnumerable<Person> People
    {
        get { _indPeople.OnGet(); return _people; }
    }

    public string FirstLetter
    {
        get { _indFirstLetter.OnGet(); return _firstLetter; }
        set { _indFirstLetter.OnSet(); _firstLetter = value; }
    }

    public IEnumerable<Person> PeopleStartingWithFirstLetter
    {
        get
        {
            if (FirstLetter == string.Empty)
                return People;
            else
                return People.Where(p => p.Name.StartsWith(FirstLetter));
        }
    }

    private Random _random = new Random();
    public void NewPerson()
    {
        _indPeople.OnSet();
        _people.Add(new Person() { Name = "Person " + _random.Next(100) });
    }
}

You just need those Independent sentry objects to ride along side your data. Tell them when the data is accessed and changed, and they will notify the controls.

For a more in-depth example, please see the latest video and download the source code.

ICommand

Watch a video on this topic, download the latest bits, and check out the source code.

WPF gives us an interface for separating commands from the visual elements that invoke them. The ICommand interface determines whether a command can be executed, and what happens when it is. To enable or disable a visual element bound to the command, the ICommand interface also exposes an event called CanExecuteChanged. Update Controls keeps track of changes and fires this event for you.

Why use command binding?
When I showed you the Presentation Model pattern, I used XAML events in code behind to handle button clicks. The problem with this approach is that it puts code in the view. This code doesn't operate on the view. In fact, it just delegates to a method on the presentation model. So why not just put it there?

Many people refer to the Presentation Model pattern as ViewModel (or Model-View-ViewModel for the palindromically inclined). That's because the ViewModel is a model designed specifically for the view. It expresses view-ish concerns, without actually being the view.

One of those concerns is the list of commands that the view can invoke. The view can bind those commands to buttons, menu items, or any other visual element. That's how you move your code from the view to the presentation model.

Create a command
WPF gives us a technique known as command binding. A command is an implementation of the ICommand interface. When it is bound to a visual element's Command property, the command controls when the visual element is enabled, and what it does when clicked.

In the latest build of Update Controls (version 2.0.3.1), I added support for command binding. It takes the form of a static class called MakeCommand. Its job is to make commands. The syntax for creating a simple command looks like this:

public ICommand AddPerson
{
    get
    {
        return MakeCommand
            .Do(() =>
            {
                Navigation.SelectedPerson = PersonList.NewPerson();
            });
    }
}

That funny arrow syntax is a lambda expression. This particular lambda expression takes no parameters, so there are empty parentheses on the left. This lambda executes a block of code, so there are curly braces on the right. This command will execute the code in those braces whenever the command is invoked, adding a person to the list and selecting them.

A slightly more complex command looks like this:

public ICommand DeletePerson
{
    get
    {
        return MakeCommand
            .When(() => Navigation.SelectedPerson != null)
            .Do(() =>
            {
                PersonList.DeletePerson(Navigation.SelectedPerson);
            });
    }
}

Here we have two lambda expressions. The first tells us when the command can be executed, and the second tells us what it does. The When lambda returns a boolean. It says that this command is enabled only when the selected person is not null. The Do clause -- the one with the curly braces -- says that the selected person is deleted from the list when the command is invoked.

The advantage of using Update Controls for command binding is that it automatically keeps the view up-to-date as the When clause changes. Since the When clause above references the SelectedPerson property, it is reevaluated every time the selected person changes. There is no need to manually fire the CanExecuteChanged event that ICommand exposes.

Bind to the command
Now that the command is exposed as a property of the navigation model, it can be bound to elements in the view. Since the navigation model is already the DataContext of the view, it's just a matter of binding the Command property. For example:

<Button Content="Add" Command="{u:Update AddPerson}"/>
<Button Content="Delete" Command="{u:Update DeletePerson}"/>

This binds the Add and Delete buttons to the AddPerson and DeletePerson commands. The When clause of these commands controls whether the buttons are enabled, and the Do clause is executed when the button is clicked.

When not to move the code
There is a button on this view that opens a new window. I have not moved this code into the presentation model, because it is concerned specifically with view logic. It creates a new view, something that the presentation model is incapable of doing. The presentation model does not have any dependency upon the view; the dependency goes the other way.

For now, I've chosen to leave that code in the view. In the future, there may be a component concerned with the flow of user interaction among different views. If that architectural concern is added, then opening a new window would become a feature of that class. Until then, the feature is more appropriate on the view than on the presentation model.

Moving the code out of the view and into the presentation model keeps it closer to the objects it needs. WPF command binding gives us a way to do that. The Update Controls MakeCommand class easily creates commands that can be bound to. These commands automatically keep the view up to date when the visual elements should be enabled or disabled.

Navigation Model

View a video of this demo. Download version 2.0.3 of Update Controls and the demo source code to follow along.

Navigation Model Intent
The Navigation Model Pattern removes dependencies between view objects and makes UI state available to presentation logic.

Use the Navigation Model Pattern when controls interact with one another in a non-trivial manner. For example, selecting an object in a list displays details in a grid. Or checking a checkbox enables an associated control.

Problem
WPF makes it really easy to bind a property of one control to a property of another. For example, if the selected item in a list box becomes the data context for a grid, the code might look like this:

<ListBox ItemsSource="{Binding People}" x:Name="personListBox">
	<!-- ... -->
</ListBox>

<Grid DataContext="{Binding ElementName=personListBox, Path=SelectedItem}">
	<!-- ... -->
	<Label Grid.Row="0" Grid.Column="0" Content="First Name:"/>
	<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding First}"/>
	<!-- ... -->
</Grid>

But direct control-to-control data binding causes trouble. Your UI is no longer composable, since controls directly reference one another. It is difficult to perform presentation logic on control properties, since the presentation model would have a reverse dependency upon the view. And it is difficult to programmatically set a control property based on user action.

Solution
Instead of binding controls directly to one another, move all of the user selection state into a Navigation Model. The navigation model is one shared location where user selection state resides. All controls that use this shared state bind to this one place. The controls don't know about one another. Any control can set the selection state, and any control can consume it. When the selection changes, all controls are updated.

Create a navigation model class
The navigation model is just a class. It has properties that correspond to the user's current selections. It has no persistent storage for this state. It survives only as long as the user's session.

In the example that we've been building, the user can select a Person. The resulting navigation model looks like this:

public class NavigationModel
{
    private Person _selectedPerson;

    #region Independent properties
    // Generated by Update Controls --------------------------------
    private Independent _indSelectedPerson = new Independent();

    public Person SelectedPerson
    {
        get { _indSelectedPerson.OnGet(); return _selectedPerson; }
        set { _indSelectedPerson.OnSet(); _selectedPerson = value; }
    }
    // End generated code --------------------------------
    #endregion
}

To generate this class, declare just the field. Select the field and press Ctrl+D, G. The Update Controls add-in will generate the property and the Independent sentry.

Expose the navigation model through the presentation model
The presentation model is a thin, transparent wrapper around the data and navigation models. It adds presentation logic where necessary, but does not hide these raw models from the view.

The presentation model initializes a reference to the navigation model in its constructor, and exposes that reference as a property. It also uses that reference in other presentation properties.

public class PresentationModel
{
    private PersonList _personList;
    private NavigationModel _navigationModel;

    public PresentationModel(PersonList personList, NavigationModel navigationModel)
    {
        _personList = personList;
        _navigationModel = navigationModel;
    }

    public PersonList PersonList
    {
        get { return _personList; }
    }

    public NavigationModel NavigationModel
    {
        get { return _navigationModel; }
    }

    public string Title
    {
        get { return "People - " +

                (_navigationModel.SelectedPerson != null ?
                    _navigationModel.SelectedPerson.Name : ""); }
    }
}

References to the data model and presentation model are not generated using Ctrl+D, G. These models don't change, so there is no need to inject Independent sentries for change tracking.

Connect controls to the navigation model
The view can access navigation model properties through the presentation model's reference. Connect the SelectedItem property of the list box to the navigation model to allow the user to change it. Connect the DataContext property of the details grid to the navigation model so that it responds to user selection.

<ListBox ItemsSource="{u:Update PersonList.People}" SelectedItem="{u:Update NavigationModel.SelectedPerson}">
	<!-- ... -->
</ListBox>

<Grid DataContext="{u:Update NavigationModel.SelectedPerson}">
	<!-- ... -->
	<Label Grid.Row="0" Grid.Column="0" Content="First Name:"/>
	<TextBox Grid.Row="0" Grid.Column="1" Text="{u:Update First}"/>
	<!-- ... -->
</Grid>

We'll want some controls to become enabled only when conditions are right. To facilitate this, we add a boolean IsPersonSelected property to the navigation model. Be sure to use the SelectedPerson property, not the _selectedPerson field, so that we get the benefit of change tracking.

public class NavigationModel
{
    private Person _selectedPerson;

    #region Independent properties // ...

    public bool IsPersonSelected
    {
        get { return SelectedPerson != null; }
    }
}

Connect this property to the IsEnabled property of selected controls. For entire groups of controls, we wrap the group in a container, and connect the property of the container to the boolean. We can't use the existing container, because it changes its own data context.

<Button Content="Delete" IsEnabled="{u:Update NavigationModel.IsPersonSelected}" Click="DeleteButton_Click" />

<StackPanel IsEnabled="{u:Update NavigationModel.IsPersonSelected}">
	<Grid DataContext="{u:Update NavigationModel.SelectedPerson}">
		<!-- ... -->
	</Grid>
</StackPanel>

Consequences
While this pattern decouples view components to make them more composable, it does so at the cost of injecting code where once only markup was necessary. This means that it is difficult for a designer to express the behavior of an application without involving a developer.

To mitigate this cost, designers and developers should agree on a contract beforehand. Obvious properties, like SelectedPerson, should be added to the navigation model immediately. Less obvious properties, like IsPersonSelected, can be added afterward. It is very difficult to refactor in a navigation model after view components have been constructed, so the architecture should start with this pattern in place.

It is also troublesome that setting the DataContext of a control makes it impossible to get back to the presentation model. If detail controls need access to presentation logic or navigation state, then an additional presentation/navigation layer must be injected. This will be demonstrated in a future post.

Syndicate content