MichaelLPerry's blog

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 IndependentList<Person> _people =
        new IndependentList<Person>();
    private Independent<string> _firstLetter =
        new Independent<string>();

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

    public string FirstLetter
    {
        get { return _firstLetter.Value; }
        set { _firstLetter.Value = 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()
    {
        _people.Add(new Person() { Name = "Person " + _random.Next(100) });
    }
}

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.

Selection Model

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

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

Use the Selection 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 Selection Model. The selection 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 selection model class
The selection 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 selection model looks like this:

public class SelectionModel
{
    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 selection model through the presentation model
The presentation model is a thin, transparent wrapper around the data and selection 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 selection 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 SelectionModel _selectionModel;

    public PresentationModel(PersonList personList, SelectionModel selectionModel)
    {
        _personList = personList;
        _selectionModel = selectionModel;
    }

    public PersonList PersonList
    {
        get { return _personList; }
    }

    public SelectionModel SelectionModel
    {
        get { return _selectionModel; }
    }

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

                (_selectionModel.SelectedPerson != null ?
                    _selectionModel.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 selection model
The view can access selection model properties through the presentation model's reference. Connect the SelectedItem property of the list box to the selection model to allow the user to change it. Connect the DataContext property of the details grid to the selection model so that it responds to user selection.

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

<Grid DataContext="{u:Update SelectionModel.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 selection model. Be sure to use the SelectedPerson property, not the _selectedPerson field, so that we get the benefit of change tracking.

public class SelectionModel
{
    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 SelectionModel.IsPersonSelected}" Click="DeleteButton_Click" />

<StackPanel IsEnabled="{u:Update SelectionModel.IsPersonSelected}">
	<Grid DataContext="{u:Update SelectionModel.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 selection model immediately. Less obvious properties, like IsPersonSelected, can be added afterward. It is very difficult to refactor in a selection 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 selection state, then an additional presentation/selection layer must be injected. This will be demonstrated in a future post.

TreeView

A WPF TreeView control can display data in any tree structure. There are essentially two kinds of tree structures: recursive and non-recursive. This example demonstrates a non-recursive tree. Download the source code and follow along.

Avoid INotifyPropertyChanged

A quick search reveals that many people have tackled the problem of implementing INotifyPropertyChanged. Here are just a few:

Here's my solution: DON'T!

You do not need to implement INotifyPropertyChanged in order to do data binding. Update Controls will do it for you. It works in Winforms, in WPF, and in Silverlight.

What's the problem, anyway?
The problem that most people see with this interface is the "magic string". You have to pass the name of the property in the event args. Many of these solutions use reflection to figure out the property name for you. That solves the magic string problem.

But that's not the real problem!

The real problem is that these techniques only work with independent properties. If one property depends upon another, then these techniques fail.

Take a closer look at PConverse's solution published in Code Project. In his RegularPerson class, DisplayName depends upon both FirstName and LastName. It has no backing field. It has no setter. It is a dependent property.

Look at the extra work he has to do in NotifiablePerson to fire PropertyChanged for DisplayName. He has to explicitly write code in the setters of both FirstName and LastName. Both of these properties have to "know" that DisplayName depends upon them.

That's a backwards dependency. FirstName and LastName should not know about DisplayName; DisplayName knows about FirstName and LastName.

Compare that to the same code using Update Controls.

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

    private Independent _indFirstName = new Independent();
    private Independent _indLastName = new Independent();

    public string FirstName
    {
        get { _indFirstName.OnGet(); return _firstName; }
        set { _indFirstName.OnSet(); _firstName = value; }
    }

    public string LastName
    {
        get { _indLastName.OnGet(); return _lastName; }
        set { _indLastName.OnSet(); _lastName = value; }
    }

    public string DisplayName
    {
        get { return FirstName + " " + LastName; }
    }
}

Niether FirstName nor LastName know about DisplayName. The dependencies are one-way and in the correct direction.

Maintainability is the problem
The above example is small and manageable. But imagine what happens when this application grows. Backwards dependencies get out of hand. They cross class boundaries and cause tight coupling between objects. Pretty soon the application is nothing but dependency management.

So please, stop inventing better ways to implement INotifyPropertyChanged. It's like inventing a better way to turn the the crank on the front of a Model T. There is no good way. Just don't do it.

Two lists

Now that Silverlight 3 has been released, I have taken the Beta designation off of Update Controls Light.

Update Controls is data binding without INotifyPropertyChanged. You never have to implement it. And you never have to consume it. And now it works with Silverlight 3.

Just like with the Winforms and WPF versions, Update Controls Light requires you to identify independent properties. An independent property is one that can be changed. It's value does not depend upon anything else. For example, a Customer's name is independent, as well as their list of invoices. You indicate that these properties are independent by creating an Independent sentry and calling OnGet() and OnSet() whenever they are accessed or changed.

public class Customer
{
    private string _name;
    private List<Invoice> _invoices = new List<Invoice>();

    private Independent _indName = new Independent();
    private Independent _indInvoices = new Independent();

    public string Name
    {
        get { _indName.OnGet(); return _name; }
        set { _indName.OnSet(); _name = value; }
    }

    public IEnumerable<Invoice> Invoices
    {
        get { _indInvoices.OnGet(); return _invoices; }
    }

    public Invoice NewInvoice(string number)
    {
        _indInvoices.OnSet();
        Invoice invoice = new Invoice(number);
        _invoices.Add(invoice);
        return invoice;
    }
}

Properties that use those independent properties are dependent upon them. Update Controls recognizes those dependencies and fires PropertyChanged events for you.

Think about that. It isn't just firing PropertyChanged for the properties that you indicate as Independent. It's firing PropertyChanged for all the properties that use those properties.

Two lists
Here's an example. This control has two lists: paid invoices and unpaid invoices.

Get Microsoft Silverlight

In a typical program, you would handle the "Paid" and "Unpaid" buttons by removing selected invoices from one list and adding them to the other. But with Update Controls Light, you just change the data model. The two lists are dependent.

public IEnumerable<Invoice> PaidInvoices
{
    get { return _payment.PaidInvoices; }
}

public IEnumerable<Invoice> UnpaidInvoices
{
    get { return _payment.Customer.Invoices.Except(_payment.PaidInvoices); }
}

The body of the UnpaidInvoices property tells the whole story. When you add an invoice to the payment, it no longer appears in UnpaidInvoices. Update Controls Light can see this and fire the right notification events.

Dependent properties never have backing storage. They just reference independent properties in their getters and -- if two-way binding is required -- setters.

Replace INotifyPropertyChanged

Update (March 2, 2011)

The information in the original post is no longer accurate. Now when Update Controls finds an object that implements INotifyPropertyChanged, it will step out of the way. The assumption is that if you implement this interface, you intend to manage your own dependencies.

If an object that implements INPC has a child object that does not, the child object is not wrapped either. Once you implement INPC, you are responsible for all of its children. If you want Update Controls to wrap a child object, you must call ForView.Wrap() inside the property getter. This is not recommended, since a view model that implements INPC should have no dependency upon Update Controls.

The original post is preserved for historical continuity.

Original post (October 10, 2009)

I recently corresponded with a new Update Controls user. He brought up some excellent points about INotifyPropertyChanged and Update Controls. The short answer is: don't mix them. Unfortunately, reality is not so cut and dried.

We started with some easy questions:

Should my view model implement INotifyPropertyChanged [when I'm using Update Controls]?

No, your view model should not implement INotifyPropertyChanged. When you call ForView.Wrap(), Update Controls implements it for you.

So ForView.Wrap() completely replaces the "{u:Update}" syntax?

Absolutely, it does. It is more Blend friendly.

But do I still need to define my Independent's using Ctrl+D, G?

Yes, the underlying dependency tracking is still exactly the same. It still requires Independent sentries, which Ctrl+D, G generates for you.

And then the hard questions began:

If I exposed properties of an object that implements INotifyPropertyChanged (for example, CslaDataProvider.IsBusy) via my ViewModel, do I need to do anything special? Or would it be so simple as:

public bool IsBusy
{
    get { return _dp.IsBusy; }
}

Unfortunately, ForView.Wrap() hides the INotifyPropertyChanged implementation of the root object or any of its properties. So simply passing through the property access would not be sufficient. Neither does the dependency tracking mechanism recognize INotifyPropertyChanged. So when the event is fired, Update Controls does not know to forward that along to the view.

If your class already implements INotifyPropertyChanged and you want to add Independent sentries too, that's fine.

public class Customer : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _name;
    private Independent _indName = new Independent();

    public string Name
    {
        get { _indName.OnGet(); return _name; }
        set { _indName.OnSet(); _name = value; FirePropertyChanged("Name"); }
    }

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

The INotifyPropertyChanged implementation will be completely ignored by Update Controls, and the Independent will be completely ignored by legacy code.

Or, if you have a legacy object and you completely control the access to its properties, you can wrap it.

public class CustomerWrapper
{
    private Customer _customer;
    private Independent _indCustomerName = new Independent();

    public CustomerWrapper(Customer customer)
    {
        _customer = customer;
    }

    public string Name
    {
        get { _indCustomerName.OnGet(); return _customer.Name; }
        set { _indCustomerName.OnSet(); _customer.Name = value; }
    }
}

But if someone else could change the controlled property without going through your code, you have to handle INotifyPropertyChanged yourself.

public class CustomerWrapper
{
    private Customer _customer;
    private Independent _indCustomerName = new Independent();

    public CustomerWrapper(Customer customer)
    {
        _customer = customer;
        _customer.PropertyChanged += (sender, e) =>
        {
            if (e.PropertyName == "Name")
                _indCustomerName.OnSet();
        };
    }

    public string Name
    {
        get { _indCustomerName.OnGet(); return _customer.Name; }
        set { /*_indCustomerName.OnSet(); Not needed anymore. */ _customer.Name = value; }
    }
}

When the event fires, you record that the property has been set. I'd love to generate a wrapper for you (something like ForViewModel.Wrap()), but I can't think of a way of doing that without hiding the underlying object properties. Maybe with some Ayende mojo I could pull it off, but I'm hoping that I never have to.

Menus

I had a twitter conversation recently with Edward Tanguay about his StackOverflow question on binding menus to an Observable Collection. Naturally, I locked on to the ObservableCollection part and didn't get the true gist of his question. I took a step back, reread his question and the provided answers, and finally caught on to the problem. I wish I could upvote Kent Boogaart's answer more than once, because it set me on a trail of discovery.

This example uses Update Controls. Download the example source code: databoundmenus.zip.

There is not just one way to make a WPF menu work. There are several techniques that you have to combine. Much of an application's menu is static. Some of it is context sensitive, and only appears in certain conditions. And in a few places, the menu items are dynamic, like recently opened files or currently open windows. Update Controls can help with all of these things.

Declarative menu structure
For the static menus, you want to declare the structure entirely in XAML. This gives you the greatest design/code separation, and the best tool support. Use Command Binding for all menu items.

<Menu DockPanel.Dock="Top">
    <MenuItem Header="_File">
        <MenuItem Header="_New" Command="{Binding FileNewCommand}"/>
        <MenuItem Header="_Open" Command="{Binding FileOpenCommand}"/>
        <MenuItem Header="_Save" Command="{Binding FileSaveCommand}"/>
        <MenuItem Header="_Close" Command="{Binding FileCloseCommand}"/>
    </MenuItem>
</Menu>


Use Update Controls MakeCommand to create all of the bindable ICommand properties. The When clause will enable and disable the menu item.

public ICommand FileSaveCommand
{
    get
    {
        // We can only save a file when one is open.
        return MakeCommand
            .When(() => _dataModel.OpenFileName != null)
            .Do(() => _dataModel.LastAction = "Save");
    }
}


Some of the menu items are not application actions, but window actions. These can be handled in code-behind.

<Separator/>
<MenuItem Header="E_xit" Click="Exit_Click"/>


private void Exit_Click(object sender, RoutedEventArgs e)
{
    Close();
}


Context sensitive menus
You want context sensitive menus to appear under certain conditions. WPF has a mechanism for that: the DataTrigger. A DataTrigger sets a control property when a data property is equal to a specific value. In this case, we want to set a MenuItem's Visibility property to Hidden when the data property IsFileOpen is False.

<Window.Resources>
    <Style x:Key="VisibleWhenFileIsOpen" TargetType="MenuItem">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsFileOpen}" Value="False">
                <Setter Property="Visibility" Value="Hidden"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>


We apply this style to any menu that is sensitive to this context.

<MenuItem Header="_Edit" Style="{StaticResource VisibleWhenFileIsOpen}">
    <MenuItem Header="Cu_t"/>
    <MenuItem Header="_Copy"/>
    <MenuItem Header="_Paste"/>
</MenuItem>

DataTriggers automatically reset. When the IsFileOpen data property is no longer False, the Visibility control property will go back to the default Visible. There is no need to create another trigger for that rule.

Dynamic menus
For recently opened files or currently open windows, you want each menu item to represent a data object. You want to bind the menu to a list.

If you bind to the raw data objects, you will have a hard time getting exactly the behavior that you want in the view. XAML is declarative, and is easiest to use when the data is already in the right format. That's where the View Model comes in.

public class RecentFileViewModel
{
    private int _index;
    private string _fileName;
    private IFileHandler _fileHandler;

    public RecentFileViewModel(int index, string fileName, IFileHandler fileHandler)
    {
        _index = index;
        _fileName = fileName;
        _fileHandler = fileHandler;
    }

    public string FileName
    {
        get { return string.Format("_{0} - {1}", _index + 1, _fileName); }
    }

    public ICommand Open
    {
        get
        {
            return MakeCommand
                .Do(() => _fileHandler.Open(_fileName));
        }
    }
}

The recent file view model presents the file name in a format suitable for the menu item. It even adds the underscore to turn the 1-based index into a hot key.

The view model also provides the command to open the file. It doesn't actually perform the operation; it delegates to a file handler and provides the context.

We provide a list of these view models based on the list of recently opened files.

public IEnumerable<RecentFileViewModel> RecentFiles
{
    get
    {
        // Create a RecentFileViewModel for each recent file.
        // The view model serves the menu item.
        return _dataModel.RecentFiles
            .Select((fileName, index) =>
                new RecentFileViewModel(index, fileName, this));
    }
}

Please note that this pattern does not work with ObservableCollection. Once you call .Select() on an ObservableCollection, it is no longer observable. This pattern only works with Update Controls.

Now we need to bind MenuItems to this collection. My first instinct was to set the ItemTemplate of the parent MenuItem to a DataTemplate containing a child MenuItem. The problem with that is that a DataTemplate controls the content of the child item, not the child item itself. So instead of setting ItemTemplate, you need to set the ItemContainerStyle.

<MenuItem Header="_Recent Files" ItemsSource="{Binding RecentFiles}">
    <MenuItem.ItemContainerStyle>
        <Style>
            <Setter Property="MenuItem.Header" Value="{Binding FileName}"/>
            <Setter Property="MenuItem.Command" Value="{Binding Open}"/>
        </Style>
    </MenuItem.ItemContainerStyle>
</MenuItem>


A WPF menu should not be defined using just one technique. If you choose something to simple, you won't be able to handle the more interactive requirements. If you choose something too complex, you loose tool support and put too much of your design in code. With this combination of techniques, you can create interactive menus with ease.

INotifyPropertyChanged is Obsolete

Please check you mailbox for the latest issue of CoDe Magazine. In it, you will find my article "INotifyPropertyChanged is Obsolete." A few things have changed since I penned those words, and now INotifyPropertyChanged is more obsolete than ever.

The article describes how to use Update Controls to replace WPF data binding. Rather than using the built-in "{Binding}" XAML extension, it tells you to use my "{u:Update}" custom extension. While this custom markup extension is still supported, it is no longer the preferred way to use Update Controls.

Blend-friendly updating
Thanks to some feedback from Paul Stovell, Microsoft MVP for Client Application Development, Update Controls now works with the "{Binding}" XAML extension. This makes it more Blend friendly. But before you give your object to the DataContext, you need to wrap it:

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        DataContext = ForView.Wrap(new PersonViewModel(new Person()));
    }
}


The wrapper implements INotifyPropertyChanged for you. It infers dependencies from your code and figures out when to fire PropertyChanged events. To help it with that inference, you need to mark your independent properties.

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

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

    public string FirstName
    {
        get { _indFirstName.OnGet(); return _firstName; }
        set { _indFirstName.OnSet(); _firstName = value; }
    }

    public string LastName
    {
        get { _indLastName.OnGet(); return _lastName; }
        set { _indLastName.OnSet(); _lastName = value; }
    }
    // End generated code --------------------------------
    #endregion

    public string FullName
    {
        get
        {
            return FirstName + " " + LastName;
        }
    }
}

The Ctrl+D, G shortcut still works. Select the fields and hit the shortcut to generate the independent properties.

Update Controls can see right through the intermediate view model. There is no bookkeeping code required. Even the dependency of Title upon FirstName and LastName is inferred.

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 FullName
    {
        get { return _person.FullName; }
    }

    public string Title
    {
        get { return "Person - " + FullName; }
    }
}

Silverlight 3
I have also ported Update Controls to Silverlight. It only works with Silverlight 3, so it is in Beta until the official release. However, it is fully operational and works just as well as the WPF version. The "{u:Update}" custom extension is not supported in Silverlight, however. You have to use the new ForView.Wrap() mechanism.

I hope you find Update Controls to be as useful as I have. You can download the source code provided in the article from CoDe Magazine, or try some demos that I've created since then:

  • Commuter - Multi-threaded iTunes synchronization sample.
  • QuickWriter - Data binding through linq queries. Uses the {u:Update} extension rather than the new ForView.Wrap().
  • UpdateControls.XAML.Test - The test app bundled with the source code.
  • Addendum Demo - The code included above.

Also be sure to watch the videos to see it in action.

Syndicate content