MichaelLPerry's blog

An ObservableCollection or BindingList of View Models

An ObservableCollection<T> will notify a view of insertions, deletions, and replacements. Conversely, a BindingList<T> will accept insertions from a view. To be most useful, these collection types should be data bound to a view. In MVVM, that means that these should be properties of a view model. Moreover, it means that these should be collections of view models.

View models are projections of model objects. If an Order has a collection of OrderLines, then an OrderViewModel should have a collection of OrderLineViewModels. In this situation, you need to keep a collection of view models synchronized with a collection of models.

Here are a couple of helper classes that do just that: MappedObservableCollection and MappedBindingList.

MappedObservableCollection takes a mapping function and a source collection. The map creates a view model for each model object. It will produce an observable collection of view models. If the source is observable (i.e. implements INotifyCollectionChanged), then it will mirror any changes in the source collection to the target collection.

public class MappedObservableCollection<TSource, TTarget>
{
    private Func<TSource, TTarget> _map;
    private IEnumerable<TSource> _sourceCollection;
    private ObservableCollection<TTarget> _targetCollection = new ObservableCollection<TTarget>();

    public MappedObservableCollection(Func<TSource, TTarget> map, IEnumerable<TSource> sourceCollection)
    {
        _map = map;
        _sourceCollection = sourceCollection;

        var notifyCollectionChanged = sourceCollection as INotifyCollectionChanged;
        if (notifyCollectionChanged != null)
            notifyCollectionChanged.CollectionChanged += SourceCollectionChanged;
        PopulateTargetCollection();
    }

    public ObservableCollection<TTarget> TargetCollection
    {
        get { return _targetCollection; }
    }

    private void SourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            // Add the corresponding targets.
            int index = e.NewStartingIndex;
            foreach (TSource item in e.NewItems)
            {
                _targetCollection.Insert(index, _map(item));
                ++index;
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            // Delete the corresponding targets.
            for (int i = 0; i < e.OldItems.Count; i++)
            {
                _targetCollection.RemoveAt(e.OldStartingIndex);
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Replace)
        {
            // Replace the corresponding targets.
            for (int i = 0; i < e.OldItems.Count; i++)
            {
                _targetCollection[i + e.OldStartingIndex] = _map((TSource)e.NewItems[i + e.NewStartingIndex]);
            }
        }
        else
        {
            // Just give up and start over.
            _targetCollection.Clear();
            PopulateTargetCollection();
        }
    }

    private void PopulateTargetCollection()
    {
        foreach (TSource item in _sourceCollection)
        {
            _targetCollection.Add(_map(item));
        }
    }
}

MappedBindingList performs a similar function, but it generates a BindingList<T>. BindingList<T> is useful for DataGrid, which allows the user to add new rows. When the user creates a new row, MappedBindingList calls a factory to get a new model object. Then it maps it into the target collection as a view model.

public class MappedBindingList<TSource, TTarget>
{
    private Func<TSource, TTarget> _map;
    private IEnumerable<TSource> _sourceCollection;
    private BindingList<TTarget> _targetCollection = new BindingList<TTarget>();
    private Func<TSource> _factory;
    
    public MappedBindingList(IEnumerable<TSource> sourceCollection, Func<TSource, TTarget> map, Func<TSource> factory)
    {
        _map = map;
        _sourceCollection = sourceCollection;
        _factory = factory;

        _targetCollection.AllowNew = true;
        _targetCollection.AllowEdit = true;
        _targetCollection.AllowRemove = true;
        _targetCollection.AddingNew += TargetCollection_AddingNew;

        var notifyCollectionChanged = sourceCollection as INotifyCollectionChanged;
        if (notifyCollectionChanged != null)
            notifyCollectionChanged.CollectionChanged += SourceCollectionChanged;
        PopulateTargetCollection();
    }

    private void TargetCollection_AddingNew(object sender, AddingNewEventArgs e)
    {
        e.NewObject = _map(_factory());
    }

    public BindingList<TTarget> TargetCollection
    {
        get { return _targetCollection; }
    }

    private void SourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            // Add the corresponding targets.
            int index = e.NewStartingIndex;
            foreach (TSource item in e.NewItems)
            {
                _targetCollection.Insert(index, _map(item));
                ++index;
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            // Delete the corresponding targets.
            for (int i = 0; i < e.OldItems.Count; i++)
            {
                _targetCollection.RemoveAt(e.OldStartingIndex);
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Replace)
        {
            // Replace the corresponding targets.
            for (int i = 0; i < e.OldItems.Count; i++)
            {
                _targetCollection[i + e.OldStartingIndex] = _map((TSource)e.NewItems[i + e.NewStartingIndex]);
            }
        }
        else
        {
            // Just give up and start over.
            _targetCollection.Clear();
            PopulateTargetCollection();
        }
    }

    private void PopulateTargetCollection()
    {
        foreach (TSource item in _sourceCollection)
        {
            _targetCollection.Add(_map(item));
        }
    }
}

These mapped collections are useful when using a framework like MVVM Light. But if you are using Update Controls, you’ll just want to use linq. It keeps your view model code cleaner, and also updates your collection when filter or sort properties change.

Hierarchical check boxes

A friend asked me to help him solve a problem with check boxes in a tree control. He had a check box on the parent items that indicated whether any of the children were checked. When you check the parent, it checks all of the children. And when you check a child, it checks the parent. His problem was that after the user checks a child, the side-effect of checking the parent caused all children to be checked.

The solution: eliminate side-effects.

Parent checked is dependent

The core of the problem was that he was treating the parent checked state as independent. In short, he was storing it in a field. In storing it, he took on the responsibility of updating it in response to events. His events, therefore, had to have side-effects.

Only store the values that the user can directly change. Calculate the rest.

Get Microsoft Silverlight

If you have Silverlight installed, you should be seeing a tree of options. These options are grouped together to form a tree. If you check or uncheck a group, then all child options are checked or unchecked. We have two types of options in our data model: groups and leaves.

image

Only a leaf has a _selected field. This is the only thing that the user can actually change. When the user checks a group, they are actually performing a macro operation: select all leaves. And when the user observes a group node, they are actually observing the aggregate state of all leaves. The group check box is dependent.

The view model

Every option in the model is associated with an OptionViewModel. This view model has a nullable boolean property that is bound to the check box. To calculate the checked state of an option, it examines all of the leaves. And when the user checks or unchecks the box, it sets all of the leaves.

public bool? IsChecked
{
    get
    {
        bool anySelected = _option.Leaves.Any(leaf => leaf.Selected);
        bool anyNotSelected = _option.Leaves.Any(leaf => !leaf.Selected);
        return
            (anySelected && !anyNotSelected) ? true :
            (!anySelected && anyNotSelected) ? false :
            (bool?)null;
    }
    set
    {
        foreach (OptionLeaf leaf in _option.Leaves)
            leaf.Selected = value ?? false;
    }
}

By storing only what the user can directly change, we have eliminated the need for side-effects. We no longer need to handle the event of checking a child in order to impose the side-effect of checking the parent. The parent’s checked state is simply dependent upon the child.

INotifyPropertyChanged is a side-effect

This example uses Update Controls to manage dependencies. An implementation that does not employ a dependency management library would have to fire PropertyChanged events up the tree. It would be cumbersome to manage these events. They have to be fired on just the right view models, and at just the right time. Firing these events would be a side-effect of storing the user’s selection.

When performing the macro operation of selecting a group, a naive implementation would fire PropertyChanged as each leaf is modified. This would cause the side-effect of firing PropertyChanged on the parent node multiple times. Update Controls collects these changes and ensures that the parent is updated only once.

Download the source code and try it for yourself.

Common mistakes while using ObservableCollection

ObservableCollection is one of the most useful classes in WPF and Silverlight data binding. Whenever you modify the collection, the view is notified. Unfortunately, it is extremely easy to misuse. These are some of the mistakes I see from beginners and experts alike.

Replacing the collection

When a view binds to an ObservableCollection, it subscribes to events from that instance. It expects to be notified when items are added, removed, or replaced within that instance of the collection. The binding is not to the property of the parent object, but to that specific instance of the collection itself.

A common mistake is to modify the parent object’s property and replace one ObservableCollection with another. Just about every person who uses ObservableCollections makes this mistake at least once. Even Scott Hanselman made this mistake on stage at Mix ‘09 (skip to 10:30). The problem is that after you swap out one ObservableCollection for a new one, the view is still bound to the old one.

A common “fix” for this problem is to fire a PropertyChanged event to notify the view that the collection has been replaced. This causes the view to unbind from the old one and rebind to the new one. In this situation, the view can’t adjust to just the items that were added or removed; it has to rebind the entire list box. Not only is this inefficient, but it also scrolls back to the top of the list rather than preserving the user’s context.

This fix completely obviates the need for an ObservableCollection in the first place. It wasn’t the collection that changed, it was the property that points to the collection. That property could have pointed to a List, and it would have had the same effect. Which brings us to the next common mistake.

Using it for static collections

A common misconception is that data binding requires ObservableCollection. This is not true. Data binding works against anything that implements IEnumerable. You can data bind a list box directly to a List, if you want.

The advantage of ObservableCollection over List is that it implements INotifyCollectionChanged. This interface raises an event whenever the collection is modified by insertion, removal, or replacement. A List does not implement this interface, so anything data bound to it will not be notified when it changes.

Not all collections change while the user is looking at them. Some collections are fixed. Others are loaded from a database or server once, and then simply displayed. If the collection doesn’t change, don’t make it an ObservableCollection. Just make it a List.

Using linq

ObservableCollection is imperative. Linq is declarative. The two cannot be used together without extra help.

Imperative code explicitly acts upon something. When using an ObservableCollection, you explicitly call Add, Remove, and other methods to change the collection. You have to decide exactly when and how to take these actions.

Declarative code implicitly generates something. When using linq, you declare what a collection will look like, how it will be filtered, mapped, and transformed. You don’t explicitly modify the collection.

These two paradigms don’t mix. Once you use linq on an ObservableCollection, it is no longer observable. There are open-source projects like Bindable Linq that bridge the gap. But without that extra help, people are often surprised when things don’t work.

Using it in the model

ObservableCollection is for data binding. In the MVVM pattern, you bind a view to a view model. So it stands to reason that ObservableCollection belongs in the view model. However, many people use it in the model as well.

Microsoft’s own code generators encourage us to make this mistake. When you add a reference to a WCF service returning a List, the proxy turns that into an ObservableCollection. When you generate classes from an Entity Framework model, you get ObservableCollections. Service calls and persistence belong in the model layer, not the view model layer. The view model needs to massage this data to make it suitable for the view, so it needs to map the model collection into its own ObservableCollection.

Modifying the collection on the background thread

When an ObservableCollection is modified, it raises an event. Events are handled synchronously. Event handlers respond on the same thread as the modification. The handler completes before the Add or Remove method returns. This means that you can’t modify an ObservableCollection in a background thread.

Most people who run into this problem realize their mistake quickly. They wrap the code that modifies the collection in a delegate, and invoke it on the UI thread. It is unfortunate that an ObservableCollection cannot be modified in a thread-safe way on a background thread. This fix puts more work than necessary on the UI thread, making it less responsive than it should be.

Conclusion

ObservableCollection is extremely easy to misuse. Even experts like Scott Hanselman get it wrong. Microsoft’s WCF and EF code generators lead us to incorrect patterns. And even when we try to do the right thing, the synchronous nature of CollectionChanged events get in our way.

My advice is to skip ObservableCollection altogether. Use Update Controls instead, and just bind to a linq query. If you find that you need to access the collection programmatically, and not just through data binding, then DependentList might be right for you. Update Controls makes it much more difficult to make these common mistakes.

Fields and collections using generics

Thanks to code contributions from David Piepgrass and Timothy Pratley, there is a new way to declare fields and collections in Update Controls. No longer do you have to declare sentries. No longer do you have to use the Ctrl+D, G code generator. Now you can use generics.

UpdateControls.Fields

  • Independent<T>
  • Dependent<T>

UpdateControls.Collections

  • IndependentList<T>
  • IndependentDictionary<Key, Value>
  • DependentList<T>

Independent fields

Models contain independent fields. User actions change these fields. Declare an independent field using Independent<T>.

public class Agent
{
    private Independent<string> _name = new Independent<string>();

    public string Name
    {
        get { return _name; }
        set { _name.Value = value; }
    }
}

The property exposes the field as the native type. Independent<T> is implicitly convertable to T, so the getter returns it directly. The opposite is not true, however, so the setter needs to assign to the Value property.

Independent collections

The Independent<T> class is useful only for single-valued fields. Do not try to combine it with a collection class. Instead, use IndependentList<T> or IndependentDictionary<Key, Value>.

public class Agency
{
    private IndependentList<Agent> _agents = new IndependentList<Agent>();
    private IndependentDictionary<Case, Agent> _leadByCase = new IndependentDictionary<Case,Agent>();

    public IEnumerable<Agent> Agents
    {
        get { return _agents; }
    }

    public void AddAgent(Agent agent)
    {
        _agents.Add(agent);
    }

    public void RemoveAgent(Agent agent)
    {
        _agents.Remove(agent);
    }

    public Agent GetLeadForCase(Case c)
    {
        return _leadByCase[c];
    }

    public void SetLeadForCase(Case c, Agent lead)
    {
        _leadByCase[c] = lead;
    }
}

These two classes are used the same as regular List<T> and Dictionary<Key, Value>. The only difference is that they participate in dependency tracking.

Dependent fields

Whereas a model contains independents, a view model contains dependents. User input does not directly change dependents. Instead, dependents are calculated. Update Controls automatically turns all view model properties into dependents, but you still might want to use Dependent<T> to cache expensive calculations.

public class AgentViewModel
{
    private Agent _agent;

    private Dependent<int> _totalCasesSolved;

    public AgentViewModel(Agent agent)
    {
        _agent = agent;

        _totalCasesSolved = new Dependent<int>(() => _agent.Cases.Count(c => c.IsSolved));
    }

    public int TotalCasesSolved
    {
        get { return _totalCasesSolved; }
    }
}

The constructor takes a lambda expression that calculates the dependent value. It is cached in the field. Dependent<T> is implicitly convertable to T, so the property returns it directly. When the independent is changed, the dependent is recalculated. You cannot set the Value of a dependent.

Dependent collections

Rather than caching one single value, a view model can also cache a collection of objects. When doing so, use DependentList<T>.

class AgencyViewModel
{
    private Agency _agency;

    private DependentList<AgentViewModel> _agentViewModels;

    public AgencyViewModel(Agency agency)
    {
        _agency = agency;

        _agentViewModels = new DependentList<AgentViewModel>(() =>
            from a in _agency.Agents
            select new AgentViewModel(a)
        );
    }

    public IEnumerable<AgentViewModel> AgentViewModels
    {
        get { return _agentViewModels; }
    }
}

The constructor takes a lambda which produces a collection. Typically, it will do so with a linq expression. The field caches the generated collection, and the property returns it as IEnumerable<T>.

DependentList<T> uses object recycling to reuse elements of the collection. If an object was already in the collection and it is returned from the linq query, then the existing object is reused. So if it in turn has dependent fields or collections, those dependents are not recalculated. To support object recycling, the elements of the collection must implement Equals, GetHashCode, and Dispose.

public class AgentViewModel : IDisposable
{
    ...
    public override bool Equals(object obj)
    {
        if (obj == this)
            return true;
        AgentViewModel that = obj as AgentViewModel;
        if (that == null)
            return false;
        return this._agent == that._agent;
    }

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

    public void Dispose()
    {
    }
}

The Dispose method will be called for objects removed from the dependent collection, so you can use it to manage any extra resources required to represent the collection in an external system. If you have no such resources, leave the body of Dispose blank.

These new generics should make it easier to declare independent fields and collections in the model, and dependent fields and collections in the view model. With them, no plug in or generated code is required.

Dependent properties

Update Controls treats all of your view model properties as dependent behind the scenes. You don’t do any extra work to manage them. But sometimes, you need to take control of dependent properties yourself. To do this, you use the Dependent class. Download the source code for this example.

Dependent sentry

As an example, we’ll create a critical path calculator. This program takes a set of tasks in a project and calculates when they will complete. The end date of a task is calculated as its start date plus its duration. We express that using a Dependent sentry.

private DateTime _endDate;
private Dependent _depEndDate;
 
public Task()
{
     _depEndDate = new Dependent(() => _endDate = CalculateEndDate());
}
 
public DateTime EndDate
{
     get
     {
         _depEndDate.OnGet();
         return _endDate;
     }
}
 
private DateTime CalculateEndDate()
{
     return StartDate.Add(Duration);
}

The Dependent sentry manages the EndDate property. When someone accesses EndDate, the sentry is notified. If the end date is out-of-date, it calculates it. StartDate is called a precedent of EndDate. Precedents can either be independent or dependent. When a precedent is dependent, we’ve constructed an indirect dependency.

Indirect dependencies

We can see from the above code that EndDate depends upon StartDate. But in our system, StartDate itself is dependent. If the task has prerequisites, it depends upon the latest end date of those other tasks. If it does not, it depends upon the start date of the project as a whole. We can express this as a Dependent as well.

private readonly Project _project;
 
private DateTime _startDate;
private Dependent _depStartDate;
 
public Task(Project project)
{
     _project = project;
     _depStartDate = new Dependent(() => _startDate = CalculateStartDate());
}
 
public DateTime StartDate
{
     get
     {
         _depStartDate.OnGet();
         return _startDate;
     }
}
 
private DateTime CalculateStartDate()
{
     DateTime? latest = null;
     foreach (Task prerequisite in Prerequisites)
         if (latest == null || latest < prerequisite.EndDate)
             latest = prerequisite.EndDate;
     return latest ?? _project.StartDate;
}

The Dependent sentry calculates the start date whenever it is out-of-date. Since CalculateEndDate accesses StartDate by the property (not by the field _startDate), it triggers this update when necessary.

Dependency chaining

imageThe start date of a task depends upon the end dates of all of its predecessors. Those end dates in turn depend upon their start dates. These dependencies chain together, linking the end date of the last task all the way back to the start date of the project. When the project start date changes, the entire chain becomes out-of-date and needs to be recalculated.

If a duration is changed in the middle of the chain, it affects only that task’s end date, and the dates of all tasks that follow. The Dependent sentry is looking at all properties accessed directly and indirectly by the Calculate methods.

If two or more properties depend upon the same precedent, then that precedent is calculated only once. A naive traversal of the graph to the right would calculate the first task twice. But the Dependent sentry is keeping track of when its precedents change. If they haven’t changed since the last time it was updated, it doesn’t recalculate. Update Controls will calculate the first task only once in order to determine the end date of the last task.

Cycles

imageIt is possible to set up a cycle in this model. You could inadvertently make two tasks prerequisites of each other. If you do, Update Controls will not be able to determine the correct order for calculating the graph. In this situation, you will not get the correct answer. Indeed, there may not be a correct answer; if the tasks both have a non-zero duration, then no dates would satisfy the equations. Update Controls will not search for a solution to a system of equations. Instead, it will just stop calculating when it discovers a dependency.

Previous versions of Update Controls threw an exception when a dependency was discovered. Unfortunately, this interacted with the user interface. When the exception was thrown, a dialog box appeared. Then, Update Controls tried to refresh the UI behind the dialog box. The dependency tracking system was in a bad state from the cycle, which caused another false cycle to be detected. The information ultimately presented to the developer did not indicate the correct cycle, and simply distracted from the real problem.

Now Update Controls simply writes “Cycle discovered during update” do the debug output. Check for this in the trace window if you ever suspect that you have created a cycle.

How does it work?

Update Controls is not magic. It determines what each property depends upon by employing a fairly simple algorithm. From there, it just hooks into data binding using the standard means.

Properties and fields

In .NET, you have fields and properties. A field stores data. A property is a pair of methods: get and set. Most people confuse them for the same thing, but they are actually quite different.

We often see properties and fields in one-to-one correspondence. We create a field called _name, then expose that through a property called Name. This pattern is so common, that Microsoft added auto-implemented properties to the C# language. But this is not the only way that fields and properties can work together.

A property could calculate values based on one or more fields. The fields could be in the same object, or in a related object. More than one property could access the same field. For example, a person having two fields - _firstName and _lastName – could have three properties – FirstName, LastName, and FullName. The fields and properties need not be in one-to-one correspondence.

Dependent and Independent

At the core of the dependency tracking algorithm are two classes:

  • Dependent keeps track of properties
  • Independent keeps track of fields

imageTo determine the value of a property, .NET executes its get method. This code is going to access one or more fields. These are the fields that the property depends upon.

The two classes set up a many-to-many relationship. A Dependent keeps track of every Independent that it accesses, and an Independent keeps track of every Dependent that accesses it.

Setup and teardown

When a Dependent (like the one in charge of FullName) is first created, it is in a state called OUT_OF_DATE. The first time that it is accessed, it sets up the two-way relationships with its Independents. To help with this, it uses a thread-local bulletin board called “Current Dependent”.

image

At first this bulletin board is empty (1). Before the Dependent calls the property’s get method, it posts itself to the bulletin board. Then it enters a state called UPDATING. The bulletin board now contains the Dependent for FullName (2).

Then it calls the get method. This method might immediately access some fields. Or it might call other methods, that call other methods, that eventually access fields. When it does, the application calls Independent.OnGet(). The Independent writes itself to the bulletin board. After the FullName get method completes, we have the _firstName and _lastName fields on the bulletin board (3).

After the Dependent calls the get method, it looks at the bulletin board. It sees that its property (FullName) depends upon the listed fields (_firstName and _lastName). So it wires up the two-way relationship between that one Dependent and those two Independents. Now the Dependent is in a state called UP_TO_DATE. This completes the setup phase.

Teardown occurs when an Independent changes. When Independent.OnSet() is called, it talks to every Dependent that has accessed it. For example, _firstName is accessed by both FirstName and FullName. All of these Dependents again become OUT_OF_DATE. They sever their relationships with all of their Independents. This is also the trigger that causes PropertyChanged events to fire, which in turn leads to the setup phase happening all over again.

Conclusion

This ebb and flow of setting up and tearing down relationships between Dependents and Independents is the basis of the dependency tracking algorithm. As you can see, there is no magic. A property simply records all of the fields that it accesses during its get method. When any of those fields change, the property is out-of-date. This is the same kind of dependency tracking that you would have to do yourself, but this all happens in code that you don’t see. That’s what makes it feel like magic.

Object Recycling

It is common in Update Controls to use linq to specify a list of view models. For example:

public IEnumerable<ContactViewModel> Contacts
{
    get
    {
        return
            from c in _addressBook.Contacts
            select new ContactViewModel(c);
    }
}

As you might imagine, this code runs every time a contact is added or deleted. Each time, it rebuilds the entire list. How is this not a performance problem?

The recycle bin

Internally, Update Controls uses object recycling. It will reuse objects from one run to the next. It does so by adding objects to a RecycleBin<T>. Then it extracts from that recycle bin as it processes new objects.

using (var bin = new RecycleBin<ContactViewModel>())
{
    foreach (ContactViewModel oldContact in _contacts)
        bin.AddObject(oldContact);
    _contacts.Clear();

    foreach (ContactViewModel newContact in _viewModel.Contacts)
        _contacts.Add(bin.Extract(newContact));
}

All of the old objects are added to the recycle bin. Then the original collection is cleared. New objects are extracted through the recycle bin before being added back into the collection. If the object is already in the recycle bin, the old one is returned. If not, the new one is used.

Equals and GetHashCode

The recycle bin uses the Equals and GetHashCode methods to find existing objects. So for this to have the desired effect, we have to implement these methods in ContactViewModel:

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

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

So even though we create a new list of ContactViewModels on every update, we reuse the old ones for the Contacts that were not added or removed.

The main advantage of object recycling is that dependent properties are preserved. None of the ContactViewModel properties need to be recalculated on the recycled objects. If ContactViewModel has any children, then those are preserved as well. This can be a significant savings for deep hierarchies.

Managing external resources

Another advantage of object recycling is that it can be used to manage an external resource. Suppose we want to represent each contact with a 3D object in a DirectX scene graph. We’ll add the following methods to ContactViewModel:

private Mesh _mesh;
private SceneGraph _sceneGraph;

public void EnsureInSceneGraph(SceneGraph sceneGraph)
{
    if (_mesh == null)
    {
        _mesh = new Mesh();
        _sceneGraph = sceneGraph;
        _sceneGraph.Add(_mesh);
    }
}

public void Dispose()
{
    if (_mesh != null)
    {
        _sceneGraph.Remove(_mesh);
    }
}

We call these methods while updating the collection.

using (var bin = new RecycleBin<ContactViewModel>())
{
    foreach (ContactViewModel oldContact in _contacts)
        bin.AddObject(oldContact);
    _contacts.Clear();

    foreach (ContactViewModel newContact in _viewModel.Contacts)
    {
        ContactViewModel extracted = bin.Extract(newContact);
        extracted.EnsureInSceneGraph(_sceneGraph);
        _contacts.Add(extracted);
    }
}

As we extract objects from the recycle bin, we ensure that the mesh is in the scene graph. If the object was already there, then nothing happens. If this is a new object, then the mesh is created.

When we leave the using block, the recycle bin is disposed. This in turn disposes all objects that were not removed from the recycle bin. An object is left over if it used to be in the collection, but it was removed. So we remove the mesh in the Dispose method.

Update Controls uses object recycling to improve performance and manage external resources. Be sure to implement Equals and GetHashCode to work well with it. And if you need some extra performance, or you need to manage your own external resources, you can use the same technique.

Presentation: Data Binding Without INotifyPropertyChanged

How would you create this tree control?

If you were using a traditional event-driven approach, you might handle the ticking of a check box by:

  • Checking all of the child nodes.
  • Walking up the tree to update all parent nodes.
  • Adding the checked option to an observable collection.
  • Adding the price of the checked option to the total price.

Consider the edge cases. The user just checked the last option in a package. You have to remove the individual options and add the package. You have to subtract the individual option prices and add the package price. Or maybe they unchecked one option in a package. Now you have to do the same steps in reverse. And you have to change the parents from solid check marks to intermediate dashes.

Event-driven programming is complex and leads to bugs. If you program using dependency instead, then problems like this become much easier.

Eliminate all PropertyChanged events from your code. Replace them with dependency tracking. Download the slides, the option tree demo, and the contact list demo.

Data bind visual states

The Visual State Manager in WPF and Silverlight is imperative. It has a method called “GoToState”. You invoke this method when you want the visual state to change. Data binding, on the other hand, is declarative. We don’t say when to do something, we just say what it should be. I’d like visual states to be more declarative.

Shane Holder asked if I had a solution to this problem. He used a “GoToStateAction” in Blend to control the visual state of a window. He wanted the visual state to be the current value of a property in his view model. His property type was an enumeration that matched the names of the visual states.

image He set the trigger to a PropertyChangedTrigger and bound it to the enumeration property. He then bound the StateName to the same property. This worked correctly when the property changed, but did not set the visual state on load.

The problem is in the name: “GoToStateAction”. This behavior is an action that is invoked on a specific event. It is imperative. You can get this working with more imperative code (eg. code behind, or a second GoToStateAction that triggers on the Window Loaded event). Or you can write a declarative behavior.

BindVisualStateBehavior

Add the following class to your WPF or Silverlight 4 project:

using System.Windows;
using System.Windows.Interactivity;
using Microsoft.Expression.Interactivity;

namespace BindingVisualStatesSL4
{
    public class BindVisualStateBehavior : Behavior<FrameworkElement>
    {
        public static DependencyProperty StateNameProperty = DependencyProperty.Register(
            "StateName",
            typeof(string),
            typeof(BindVisualStateBehavior),
            new PropertyMetadata(VisualStatePropertyChanged));
        private bool _initialized = false;

        public string StateName
        {
            get { return (string)GetValue(StateNameProperty); }
            set { SetValue(StateNameProperty, value); }
        }

        public void UpdateVisualState(string visualState)
        {
            if (AssociatedObject != null)
            {
                FrameworkElement stateTarget;
                if (VisualStateUtilities.TryFindNearestStatefulControl(AssociatedObject, out stateTarget))
                {
                    bool useTransitions = _initialized;
                    VisualStateUtilities.GoToState(stateTarget, visualState, useTransitions);
                    _initialized = true;
                }
            }
        }

        private static void VisualStatePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ((BindVisualStateBehavior)obj).UpdateVisualState((string)args.NewValue);
        }
    }
}

Note: this does not work in Silverlight 3 (and hence Windows Phone 7). Behavior properties were not bindable until 4.

This class uses the following assemblies, so add references if necessary:

  • Microsoft.Expression.Interactions
  • System.Windows.Interactivity

That first assembly comes from Blend, so you might not have it if you don’t have Blend installed. But then again, if you are not using Blend, binding visual states declaratively is the least of your problems. Defining those visual states manually in XAML is going to be a chore.

image Once you add this class (and compile), then it will appear in the Blend assets pane. Drag this behavior onto a component on your art board. Then bind the StateName property. You can use either a string or an enumeration. The names of the enumeration values must match the names of your visual states.

Compass example

Download the attached source code for an example of this behavior in both WPF and Silverlight 4. The example shows a compass. Select a direction radio button to move the compass needle.

Get Microsoft Silverlight

Both the radio buttons and the visual state are bound to a simple data model. I’m not even using MVVM.

public class Compass : INotifyPropertyChanged
{
    private CompassDirection _direction = CompassDirection.East;

    public CompassDirection Direction
    {
        get { return _direction; }
        set
        {
            if (_direction != value)
            {
                _direction = value;
                FirePropertyChanged("Direction");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

I use a value converter to bind the enumeration to the IsChecked property of the radio buttons. I found this technique on Stack Overflow.

Update Controls

You might have noticed in the code above that I did not use Update Controls. Instead, I implemented the dreaded INotifyPropertyChanged. While the BindVisualStateBehavior will work with Update Controls, I wanted to demonstrate that it did not depend upon it.

Update Controls is all about replacing imperative code with declarative code. Just like GoToState, PropertyChanged is imperative. You have to fire the event at just the right time. So in spirit, this behavior is related to Update Controls.

In practice, however, the behavior is useful even if you don’t use Update Controls. I was originally planning on making it part of the library, but instead I decided to simply post the source code. Please post a comment if you believe I should include it.

View Models in F#

A View Model is a projections of one or more models onto the view. As projections, they should have no mutable state of their own. In C# and other object-oriented languages, mutable state is the default. In F# and other functional languages, it is discouraged. So F# is actually a better language for expressing View Models than is C#.

Constructors

An F# View Model has less ceremony than its C# counterpart. Here is the constructor of a C# view model that represents a Product from a Customer’s point-of-view:

public class ProductViewModel
{
    private Product _product;
    private Customer _customer;

    public ProductViewModel(Product product, Customer customer)
    {
        _product = product;
        _customer = customer;
    }
}

The equivalent code in F# is:

type ProductViewModel(product: Product, customer: Customer)

F# automatically pulls the parameters into context, so we don’t have to store them.

Properties

A View Model exposes properties for data binding. The values of these properties are calculated based on the models. In C#, a calculated property looks like this:

public decimal Price
{
    get
    {
        return Decimal.Round((_product.BasePrice * (_customer.IsPreferred ? 0.9m : 1.0m)), 2);
    }
}

We have to declare the property type and use two layers of punctuation. In F#, it looks like this:

member this.Price =
    System.Decimal.Round((product.BasePrice * if customer.IsPreferred then 0.9m else 1.0m), 2)

F# infers the type from the expression. Indentation removes the need for much of the punctuation.

Some properties are bidirectional. When the user sets them, they modify the model. In C#:

public string CustomerName
{
    get
    {
        return _customer.Name;
    }
    set
    {
        _customer.Name = value;
    }
}

And in F#:

member this.CustomerName
    with get() = customer.Name
    and set(value) = customer.Name <- value

Here the fact that properties are atypical in F# is starting to show. The “value” parameter is explicitly declared, as opposed to being a built-in keyword in C#.

Collections

A View Model exposes other View Models. So when we need a list, we should project a collection of Model objects into a collection of View Model objects. In C#, we do this with the Linq “select”.

public IEnumerable<ProductViewModel> Products
{
    get
    {
        return from p in _catalog.Products select new ProductViewModel(p, _customer);
    }
}

Since Linq is functional in nature, this projection is succinct. In F#, the equivalent is:

member this.Products = Seq.map (fun p -> ProductViewModel(p, customer)) catalog.Products

Seq.map is equivalent to “select”. It takes a mapping function and applies it to all elements in the source collection. The type inference of IEnumerable<ProductViewModel> is nice, but otherwise it’s even.

Equivalence

Whenever you bind both the ItemsSource and the SelectedItem of an items control, you need to ensure that the selected item is equal to one of the items in the collection. When projecting into new View Models, we create new identities. We therefore need to replace identity comparison with value comparison. Here’s how we do that in C#:

public override bool Equals(object obj)
{
    ProductViewModel that = obj as ProductViewModel;
    if (that == null)
        return false;
    return _product == that._product;
}

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

We only compare the product because we know that all items in the list are for the same customer. In F#, we have to write this:

member this.Product = product
override this.Equals(obj) =
    match obj with
        | :? ProductViewModel as that -> that.Product = product
        | _ -> false
override this.GetHashCode() = product.GetHashCode()

Since “product” is in the scope of the closure, it is not an actual member of the View Model. That’s why we can’t access “that.product” directly. Instead, we define a member “Product” as an alias to the parameter. We need to do this anyway, since the code that uses ProductViewModel need to know the actual Product of the selected item, but it might surprise you at first.

I actually expected F# to do much better at this part. Since the class has no mutable values, I expected that it would assume that two objects with the same parameters are equal. Other functional languages have a feature called “memoization” that treats all closures having the same parameters as equal, even identical.

Commands

Update Controls gives you the MakeCommand class, which generates an ICommand from a couple of functions. To use this, you have to add the following references to your ViewModels project:

  • UpdateControls
  • UpdateControls.XAML
  • PresentationCore

Like Linq, MakeCommand is functional in nature. Here is how it is used in C#:

public ICommand PlaceOrder
{
    get
    {
        return MakeCommand
            .When(() => _navigation.SelectedProduct != null)
            .Do(() => _customer.PlaceOrder(_navigation.SelectedProduct));
    }
}

The F# syntax is nearly identical:

member this.PlaceOrder =
    MakeCommand
        .When(fun () -> navigation.SelectedProduct <> null)
        .Do(fun () -> customer.PlaceOrder(navigation.SelectedProduct))

The main thing to recognize here is that C# is more forgiving; lambda expressions that return values (i.e. Func<T>) can be used as actions. F# does not allow this. So be sure that your method returns void. Alternatively, you could do something with that value, like assigning it to a navigation model property.

F# as View Model layer

Even though there are some places where F# is simply on par with C#, I believe the strengths of F# are compelling enough to recommend using it in the View Model layer. All of the modern XAML-based user interface technologies (WPF, Silverlight 4, Windows Phone 7) support F#. The syntax may be a little unfamiliar, but perhaps these examples will help get you started. Download the code and try it for yourself.

Syndicate content