Colin Eberhardt's Technology Adventures

Everything you wanted to know about databinding in WPF, Silverlight and WP7 (Part One)

April 5th, 2012

OK, so the title is a little ambitious, but there is nothing wrong with setting yourself lofty aims! Because of the depth of this topic I have decided to split this tutorial up into a series of blog posts, each of which explore a different aspect of the binding framework.

I don’t usually write tutorial blog posts and series, preferring instead to develop new controls or novel techniques. However, I really felt this subject needed an in-depth tutorial. Databinding is a fundamental part of the WPF, Silverlight and the Silverlight for Windows Phone 7 frameworks. It is a powerful concept that once mastered allows you to write concise and elegant code. Yet for all its power, it is a little complex and that is my reason for launching into this blog series.

The rough outline for this series is as follows:

  • Part One – Life before binding, INotifyPropertyChanged and creating bindings in code-behind
  • Part Two – The binding markup extensions, the DataContext and path syntax
  • Part Three – Other binding sources, ElementName, TemplatedParent, TemplateBinding
  • Part Four – Value converters
  • Part Five – List binding

Life before binding

To understand what databinding is and the service it provides us with, it is worth looking at how you wire-up a user-interface without using databinding. We’ll start with a simple model object, or business object, and see how we can take the properties that this object exposes and display them in the UI using standard controls. We will also see how we can respond to event raised by these controls in order to update our model.

Note, that I am making the assumption that your code will contain some sort of model object. This doesn’t have to be the case! You could store your data within the UI controls directly, however this rapidly becomes un-maintainable. There are a whole host of UI patterns that have been developed in order to keep the model and the view separate (MVP, MVC, MVVM etc…)

We’ll look at how to manage the interactions between the model and the view without the help of a binding framework. For our example we’ll look at a very simple UI which displays the details of an event, its name and the date of the event:

The model that supports this view is shown below:

/// <summary>
/// A simple model object that represents an event
/// </summary>
public class EventModel : INotifyPropertyChanged
{
  private string _title;
 
  /// <summary>
  /// Gets / sets the event title
  /// </summary>
  public string Title
  {
    get { return _title; }
    set
    {
      if (value == _title)
        return;
 
      _title = value;
      OnPropertyChanged("Title");
    }
  }
 
  private DateTime _date;
 
  /// <summary>
  /// Gets / sets the date of this event
  /// </summary>
  public DateTime Date
  {
    get { return _date; }
    set
    {
      if (value == _date)
        return;
 
      _date = value;
      OnPropertyChanged("Date");
    }
  }
 
  public event PropertyChangedEventHandler  PropertyChanged;
 
  protected void OnPropertyChanged(string propertyName)
  {
    if (PropertyChanged != null)
    {
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

In our case the model implements INotifyPropertyChanged, allowing us to detect changes in its properties. We will use this to update the view when the model changes.

The view has the following XAML (with the various layout properties omitted for clarity):

<TextBlock Text="Name:"/>
<TextBox x:Name="EventTitle"
          TextChanged="EventTitle_TextChanged"
 
<TextBlock Text="Date:"/>
<sdk:DatePicker x:Name="EventDate"
                SelectedDateChanged="EventDate_SelectedDateChanged"/>
 
<Button Content="Modify Event"
        Click="Button_Click"/>

The code-behind that supports this view is given below:

public partial class MainPage : UserControl
{
  private EventModel _event;
 
  public MainPage()
  {
    InitializeComponent();
 
    // create a model object
    _event = new EventModel()
    {
      Date = new DateTime(2011, 7, 1),
      Title = "Silverlight User Group"
    };
 
    // copy our model object state to the UI
    EventDate.SelectedDate = _event.Date;
    EventTitle.Text = _event.Title;
 
    // 'listen' to changes in the model
    _event.PropertyChanged += Event_PropertyChanged;
  }
 
  /// <summary>
  /// Handles changes in the model, reflecting this change in the UI (view)
  /// </summary>
  private void Event_PropertyChanged(object sender, PropertyChangedEventArgs e)
  {
    if (e.PropertyName == "Title")
    {
      EventTitle.Text = _event.Title;
    }
    if (e.PropertyName == "Date")
    {
      EventDate.SelectedDate = _event.Date;
    }
  }
 
  /// <summary>
  /// Handles the TextChanged event updating the model accordingly
  /// </summary>
  private void EventTitle_TextChanged(object sender, TextChangedEventArgs e)
  {
    _event.Title = EventTitle.Text;
  }
 
  /// <summary>
  /// Handles the SelectedDateChanged event updating the model accordingly
  /// </summary>
  private void EventDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
  {
    _event.Date = EventDate.SelectedDate.Value;
  }
 
  private void Button_Click(object sender, RoutedEventArgs e)
  {
    // make some change to our event
    _event.Title = _event.Title.ToLower();
    _event.Date = _event.Date.AddDays(1);
  }
}

In order to wire-up the model with our view, the above code performs the following distinct tasks for each of the model’s properties:

  1. Sets the state of the UI controls to the initial state of the model. In the above example this is done in the constructor.
  2. Subscribes to the event that the UI control exposes to indicate a change in state. For the TextBox this is the TextChanged event, for the DatePicker this is the SelectedDateChanged event. When a change occurs, the UI state used to update the mode.
  3. Subscribes to PropertyChanged events from the model object. The handler for this event detects the property that has changed and updates the state of the corresponding UI control.

If we consider the model object to be the source of the data and the UI control to be the target. We can see that we have three separate flows of data:

The code for each of these three steps is distributed throughout our code, in the constructor and a variety of event handler. For each model property that we wish to expose to our user via the view, we have to add code to perform each of these three tasks. This leads to code that is hard to maintain and dataflow that are hard to trace.

Databinding – less code, greater clarity

Databinding provides an alternative to the manual coupling of the model to the UI controls in our view. The idea being that the binding framework takes care of all three of the tasks above. We simply state that we wish to synchronise a model property with a property of a UI control, and it does the rest. Our complex diagram above simply becomes the following:

Changes in the source property values are pushed to the target property by the binding framework, and (optionally) changes in the target are pushed to the source.

Modifying the code for our example to use the WPF / Silverlight framework results in the following code:

public MainPage()
{
  InitializeComponent();
 
  // create a model object
  _event = new EventModel()
  {
    Date = new DateTime(2011, 7, 1),
    Title = "Silverlight User Group"
  };
 
  // bind the Date to the UI
  EventDate.SetBinding(DatePicker.SelectedDateProperty, new Binding("Date")
  {
    Source = _event,
    Mode = BindingMode.TwoWay
  });
 
  // bind the Title to the UI
  EventTitle.SetBinding(TextBox.TextProperty, new Binding("Title")
  {
    Source = _event,
    Mode = BindingMode.TwoWay
  });
}

This is a big improvement on the previous ‘manual’ example where three separate event handlers were required to maintain synchronization between the model and the view. Databinding allows us to declare how the model is connected to the view, with the databinding framework taking care of the mechanics.

We’ll take a closer look at the databinding syntax in order to understand its various component parts. We can highlight these components by re-writing one of the bindings as follows:

FrameworkElement targetObject = EventTitle;
DependencyProperty targetProperty = TextBox.TextProperty;
object sourceObject = _event;
string sourceProperty = "Title";
 
var binding = new Binding(sourceProperty)
{
  Source = sourceObject,
  Mode = BindingMode.TwoWay
};
targetObject.SetBinding(targetProperty, binding);

From the above we can clearly see the following components:

  • The source object – this is the object which contains the data which we want to render within the UI
  • The source property – the property of the above object which we wish to render
  • The target object – this is a UI control which has a property which we are going to use to display our model property
  • The target property – the property of the UI control which visualises our data
  • The binding - this is used to indicate the source and source property, together with other information relating to the binding like the direction of data flow, value converters etc… (more on these later).
  • SetBinding – this is the method used to associate a databinding with a specific property on the target. Note that the first argument is the dependency property that is defined on TextBox and is public static.

Once a binding has been created and associated with a dependency property, the initial value is propagated from the source to the target. Following this, if the source object implements INotifyPropertyChanged, subsequent changes in the source property value are automatically propagated. If a BindingMode.TwoWay binding is used, changes to the target property, which typically occur due to user interactions, are propagated from the target to the source.

A brief digression into dependency properties

As you can see from the above, databinding is a feature of WPF and Silverlght dependency property mechanism. The type of properties that developers are used to from other .NET languages are typically termed ‘CLR properties’ (Where CLR refers to the Common Language Runtime) so that we know which type of property we are talking about!

CLR properties are simply shorthand for methods used to access a backing field. You cannot use the databinding framework to bind together two CLR properties. Dependency properties are something much more powerful, they provide property inheritance within the visual tree, animation support, precedence rules, coercion and, most importantly for the purposes of this article, databinding.

In the example below, a dependency property ‘TotalGoals’ is defined on a dependency object. By convention, this dependency property is exposed as a public static field on the dependency object. It is this static field that we use to identify the dependency property when binding to it:

public class MatchResult : DependencyObject
{
  /// <summary>
  /// Identifies the TotalGoals Dependency Property.
  /// <summary>
  public static readonly DependencyProperty TotalGoalsProperty =
      DependencyProperty.Register("TotalGoals", typeof(int),
      typeof(MatchResult), new PropertyMetadata(0));
 
}

Once a dependency property has been defined, its value can be get / set via the GetValue / SetValue methods:

var result = new MatchResult();
// set the property
result.SetValue(MatchResult.TotalGoalsProperty, 10);
 
// get the property
Debug.WriteLine(result.GetValue(MatchResult.TotalGoalsProperty))

Because the syntax to get or set a dependency property is not terribly friendly, using the GetValue / SetValue methods, dependency objects typically provide CLR properties that wrap the dependency property access, providing a better API for manipulating the state form code-behind.

/// <summary>
/// Gets or sets the total score. This is a dependency property.
/// </summary>
public int TotalScore
{
  set
  {
    SetValue(MatchResult.TotalGoalsProperty, value);
  }
  get
  {
    return (int)GetValue(MatchResult.TotalGoalsProperty);
  }
}

However, this is purely convention.

Whilst the target for a binding must be a dependency property (which must be defined on a dependency object), the source can be either a dependency property or a CLR property. In practice, unless you are creating your own controls, you will not need to create your own dependency properties. Instead, you will be binding your model to the properties of the various UI elements that are supplied with the WPF / Silverlight frameworks, for example TextBlock.Text. These are all dependency properties.

A quick note about INotifyPropertyChanged

Whilst dependency properties always notify the binding framework of any changes in value, CLR properties only notify of changes if the class which the belong to implements the INotifyPropertyChanged interface (as the class used in the example above does). It is not mandatory that you implement this interface, or raise the PropertyChanged event, for properties that your bind to your UI. However, if you do not, the binding framework will only perform a one-time update, pushing the property value from source to target at the point when the binding is created.

BindingModes

You can specify which direction you want property changes to propagate by setting the BindingMode on a binding. This is probably easiest to illustrate with a simple diagram:

OneWay bindings only propagate changes in the source value to the target (assuming the source implements INotifyPropertyChanged), whereas a TwoWay binding propagates changes in both directions, ensuring that the two values are always synchronized. There are a few other binding modes (OneWayToSource, OneTime…) but one / two way are by far the most commonly used.

WARNING: The default BindingMode for Silverlight is OneWay, whereas in WPF it is BindingMode.Default which means … it depends! From MSDN:

“The default value varies for each dependency property. In general, user-editable control properties, such as those of text boxes and check boxes, default to two-way bindings, whereas most other properties default to one-way bindings.”

This is very confusing if you are writing cross-platform WPF / Silverlight code! In this case I would always recommend specifying the BindingMode explicity.

Summary

So far we have seen what life was like before databinding, where we had to write code to handle changes from both the source and target properties, manually synchronizing the two. With binding, the framework handles this for us, allowing for a more declarative approach to wiring-up our UI to the model that backs it (you do have a model behind your view don’t you?!).

However, you might be wondering why there has been no mention of binding in XAML yet? This was intentional, I wanted to first show how bindings work under-the-hood, introducing the concept of source and target, before leaping into creating them in XAML … which is the subject of the next blog post …

You can download the example code here: BindingExamples.zip

Regards, Colin E.

A Simple Pattern for Creating Re-useable UserControls in WPF / Silverlight

February 6th, 2012

This blog post provides step-by-step instructions for creating a user control, which exposes bindable properties, in WPF and Silverlight. The post covers dependency properties, and how to manage DataContext inheritance.

When building user interfaces you will often find yourself repeating the same UI patterns across your application. After all, users like to be presented with a consistent interface, so re-use makes sense. The WPF and Silverlight frameworks provide custom controls and user controls as a mechanism for re-using blocks of UI elements. Custom controls are rather special, with the logic being de-coupled from the XAML in order to support templating. For most needs, the simpler user control is more appropriate.

From participating in sites like StackOverflow I have noticed that whilst most people understand how to create a user control, which allows them to ‘stamp out’ the same XAML in multiple places, many struggle with how to make their user controls flexible by exposing properties that configure how it looks or behaves. This blog post will walk through a simple example, showing you how to create a user control, add dependency properties, wire them to the user control XAML and make a truly re-useable control.

We’ll start with a very simple example, an application that displays a simple form field which consists of a name and a value:

<UserControl x:Class="UserControlExample.MainPage"
    ...>
 
  <Grid x:Name="LayoutRoot" Background="White">
 
    <StackPanel Orientation="Horizontal"
                VerticalAlignment="Top">
      <TextBlock Text="Shoesize:"
                 Width="100"
                 VerticalAlignment="Center"/>   
      <TextBox Text="{Binding Path=Shoesize}"
               Width="100"/>
    </StackPanel>
  </Grid>
</UserControl>

This UI is bound to a simple model object that implements INotifyPropertyChanged (not shown for the sake of brevity):

public class ModelObject : INotifyPropertyChanged
{
  public int Shoesize {...}
 
  public double Height {...}
}

The constructor instantiates the model object and sets it as the DataContext:

public MainPage()
{
  InitializeComponent();
 
  var model = new ModelObject()
  {
    Shoesize = 12,
    Height = 34.5
  };
 
  this.DataContext = model;
}

This produces the expected behaviour, a label and a text field that allows you to edit the Shoesize property:

Let’s say we want to allow the user to edit the Height property as well. We could cut and paste our current XAML, but this will only cause maintenance issues in future. Instead, the preferred approach would be to move the XAML into a user control, allowing it to be re-used.

The first step is to create a new user control, FieldUserControl, and move our XAML into there:

<UserControl x:Class="UserControlExample.FieldUserControl"
    ...>
  <StackPanel Orientation="Horizontal">
    <TextBlock Text="Shoesize:"
               Width="100"
               VerticalAlignment="Center"/>
    <TextBox Text="{Binding Path=Shoesize}"
             Width="100"/>
  </StackPanel>
</UserControl>

We can now replace the XAML we have moved with an instance of this user control:

<UserControl x:Class="UserControlExample.MainPage"
    xmlns:local="clr-namespace:UserControlExample"
    ...>
  <Grid x:Name="LayoutRoot">
    <local:FieldUserControl VerticalAlignment="Top"/>
  </Grid>
</UserControl>

Compiling and running this code proves that this still works; we can see the model property and edit it:

For trivial user controls this is all we need to do. However, in most cases, like this one, you will find that there are some elements of your user control that you wish to configure. In order to use this control for editing the Height property we need to make the label configurable. We do this by adding a Label property to our FieldUserControl.

This is where things get a bit tricky! Ideally this property should support binding, just like any other property of the framework UI controls. The WPF / Silverlight binding framework revolves around the concept of dependency properties, you can make any property the source of a binding, but the target must be a dependency property (DP). So let’s go ahead and add a Label dependency property to our user control:

public partial class FieldUserControl : UserControl
{
  #region Label DP
 
  /// <summary>
  /// Gets or sets the Label which is displayed next to the field
  /// </summary>
  public String Label
  {
    get { return (String)GetValue(LabelProperty); }
    set { SetValue(LabelProperty, value); }
  }
 
  /// <summary>
  /// Identified the Label dependency property
  /// </summary>
  public static readonly DependencyProperty LabelProperty =
      DependencyProperty.Register("Label", typeof(string),
        typeof(FieldUserControl), new PropertyMetadata(""));
 
  #endregion
 
  public FieldUserControl()
  {
    InitializeComponent();
  }
}

A lot of code isn’t it? It’s all boiler-plate stuff, you just have to live with it (I’d recommend either using code-snippets, or code generation for DPs)

We can now go ahead and bind the label text to this property:

<UserControl x:Class="UserControlExample.FieldUserControl"
    ...>
  <StackPanel Orientation="Horizontal" x:Name="LayoutRoot">
    <TextBlock Text="{Binding Path=Label}"
               Width="100"
               VerticalAlignment="Center"/>
    <TextBox Text="{Binding Path=Shoesize}"
             Width="100"/>
  </StackPanel>
</UserControl>

However, if you compile and run the above code, you’ll find that it doesn’t work. The model property value is still displayed but the label is not.

So why is this?

Bindings have both a source and a target; where the binding framework is responsible for handling change notifications from the source and (optionally) the target, keeping the two synchronized. The bindings in our FieldUserControl have a value for the Path, which specifies the target, but what is the source?

If you create a binding in XAML but do not specify the source (which is probably the most common use case), the source will be set to the DataContext of the control the binding has been specified on. The DataContext is inherited down the visual tree, from each control’s parent to child. The DataContext is most often set to a view model or business / model object, as in our case where the top level control, the MainPage, has its DataContext set to an instance of ModelObject.

As a result, the DataContext for FieldUserControl and all of its child elements is also ModelObject. This is why our Value binding is failing. Value is a property of FieldUserControl, not our model object.

So how do we go about fixing this? Most people’s first reaction is to set the DataContext of the user control to itself (I distinctly recall doing this myself the first time I encountered this problem!). We’ll find out later that this is a mistake – but for now let’s just go with it!

public FieldUserControl()
{
  InitializeComponent();
 
  this.DataContext = this;
}

With the DataContext of the control now set to itself, our label is now working:

However, now our value has disappeared! Again, this is a DataContext issue, the binding in our user control is on a Shoesize property, whilst the DataContext is now the FieldUserControl instance.

This is not such a big problem, we were going to have to change that anyway, a hard-coded binding to the Shoesize property means that we cannot re-use this control to edit other properties of the model object.

So we add another dependency property to our user control. We already have the Label dependency property, we now add a Value property:

public partial class FieldUserControl : UserControl
{
  #region Label DP
 
  ...
 
  #endregion
 
  #region Value DP
 
  /// <summary>
  /// Gets or sets the Value which is being displayed
  /// </summary>
  public object Value
  {
    get { return (object)GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }
  }
 
  /// <summary>
  /// Identified the Label dependency property
  /// </summary>
  public static readonly DependencyProperty ValueProperty =
      DependencyProperty.Register("Value", typeof(object),
        typeof(FieldUserControl), new PropertyMetadata(null));
 
  #endregion
 
  public FieldUserControl()
  {
    InitializeComponent();
 
    this.DataContext = this;
  }
}

This value property is bound to the user control UI as follows:

<UserControl x:Class="UserControlExample.FieldUserControl"
    ...>
  <StackPanel Orientation="Horizontal" x:Name="LayoutRoot">
    <TextBlock Text="{Binding Path=Label}"
               Width="100"
               VerticalAlignment="Center"/>
    <TextBox Text="{Binding Path=Value}"
             Width="100"/>
  </StackPanel>
</UserControl>

The idea here is that the exposed Value property ‘relays’ the value of the binding in our MainPage.xaml, which now has a binding which tells us which model object property is being displayed in our user control:

<Grid>
  <StackPanel Orientation="Vertical"
              HorizontalAlignment="Left"
              Margin="10">
    <local:FieldUserControl VerticalAlignment="Top"
                            Label="Height:"
                            Value="{Binding Height}"/>
    <local:FieldUserControl VerticalAlignment="Top"
                            Label="Shoesize:"
                            Value="{Binding Height}"/>
  </StackPanel>
</Grid>

If you compile and run this code you will find that … it doesn’t work!

Remember earlier when I said that setting the user control’s DataContext to itself is a mistake? We have just found out why!

The source of a binding is the DataContext of the control it is defined upon. In our MainPage.xaml we have attempted to bind the Value property of the FieldUserControl to the Height property on our model object. However, the code within the FieldUserControl constructor means that it no longer inherits its parent’s DataContext (i.e. our model object), so this binding does not work.

This problem can be fixed by setting the DataContext of the FieldUserControl’s root element to itself.

Note that the user control has a StackPanel as its root element and that this is named LayoutRoot:

<UserControl x:Class="UserControlExample.FieldUserControl"
    ...>
  <StackPanel Orientation="Horizontal"
              x:Name="LayoutRoot">
    ...
  </StackPanel>
</UserControl>

We change the constructor so that it sets the LayoutRoot DataContext to itself.

public FieldUserControl()
{
  InitializeComponent();
 
  //this.DataContext = this;
  LayoutRoot.DataContext = this;
}

This means that the FieldUserControl still inherits its parent’s DataContext, so bindings to our model object will work. Furthermore, the FieldUserControl and its children all have the FieldUserControl as their DataContext, so their bindings work also:

Finally, we’re done!

If the technique of binding the layout root of the user control to itself is a bit confusing – the following diagram, which shows the visual tree of our simple application, might help:

Again, notice that the DataContext of FieldUserControl is inherited from its parent. This means that any bindings we add to FieldUserControl have the ModelObect as their source.

We can now create multiple instances of FieldUserControl to edit different properties:

<UserControl x:Class="UserControlExample.MainPage"
    xmlns:local="clr-namespace:UserControlExample"
    ...>
 
  <Grid>
    <StackPanel Orientation="Vertical"
                HorizontalAlignment="Left"
                Margin="10">
      <local:FieldUserControl VerticalAlignment="Top"
                              Label="Height:"
                              Value="{Binding Height}"/>
      <local:FieldUserControl VerticalAlignment="Top"
                              Label="Shoesize:"
                              Value="{Binding Shoesize}"/>
    </StackPanel>
  </Grid>
</UserControl>

With an update of the FieldUserControl styling, the result looks like this:

We now have a truly re-useable user control!

As an aside, for bonus points, you can bind the layout root DataContext without any code-behind by using an ElementName binding as follows:

<UserControl x:Class="UserControlExample.FieldUserControl"
             x:Name="parent" ...>
  <StackPanel Orientation="Horizontal"
              DataContext="{Binding ElementName=parent}">
    <TextBlock Text="{Binding Path=Label}"
               Width="100"
               VerticalAlignment="Center"/>
    <TextBox Text="{Binding Path=Shoesize}"
             Width="100"/>
  </StackPanel>
</UserControl>

Or, in WPF you could event use a RelativeSource FindAncestor binding, with AncestorType set to the type of FieldUserControl (but that would just be showing off!).

Hopefully this blog post will help anyone who is confused about how to create user controls which expose properties in WPF or Silverlight.

You can download the sourcecode for the example: UserControlExample.zip

Regards, Colin E.

Using a Grid as the Panel for an ItemsControl

November 15th, 2010

In this blog post I look at how to use a Grid as the ItemsPanel for an ItemsControl, solving a few of the issues that crop up along the way.

The Grid is probably the most useful of Silverlight and WPF’s panels (panels are elements which provide a mechanism for laying out their children). The ItemsControl provides a mechanism for generating multiple instances of some template based on the data that is bound to it. The ItemsControl ‘concept’ is highlight versatile, and is used as the foundation for many of the framework controls, I find myself using it all the time.

Isn’t it a shame that Grid and ItemsControl don’t play together nicely?

So what do I mean by this? I am sure that if you have ever tried to generate Grid a layout using an ItemsControl you will know what I am talking about, but if not, here’s a very brief summary of the problem. An ItemsControl manages a number of child elements, you can configure the type of panel the ItemsControl adds children to via its ItemsPanel property. If I have a list of strings which I want to render using a Grid, I might expect the following to work … in XAML:

<ItemsControl ItemsSource="{Binding}">
  <!-- host the items generated by this ItemsControl in a grid -->
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <Grid/>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <!-- render each bound item using a TextBlock-->
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding}"/>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

And in code-behind:

this.DataContext = new string[]
  { "one", "two", "three", "four", "five"  };

So what is wrong with the above? There are a couple of problems:

  1. When using a Grid you must add the required number of rows / columns via the RowDefinitions ColumnDefinitions properties. In the above example what we really want is for the grid rows to be added dynamically based on the number of items in the bound data. Unfortunately this is not supported either by the Grid or the ItemsControl.
  2. The second problem is that items within a grid must declare the row / column that they occupy via the Grid.Row and Grid.Column attached properties. You might think that you could add a Grid.Row property to the TextBlock in the above example, binding it to some other property of the bound collection. However, this will not work because the TextBlock elements are not added into the grid directly; each one is added as the content of a ContentPresenter which is generated for us.

The above two problems mean that it is not possible to use a Grid as the panel within an ItemsControl. In this blog post I will show a solution to these problems …

Dynamically adding RowDefinitions

The first problem to overcome is how to dynamically add the required number of RowDefinitions to our Grid. To support this I added an attached property ItemsPerRow, which upon attachment handles the LayoutUpdated event. This event is fired when items are added to the grid, this enables us to compute the number of RowDefinitions that are required, and also to assign a row index to each of the Grid’s children. The following code is the property changed handler for the attached ItemsPerRow property:

/// <summary>
/// Handles property changed event for the ItemsPerRow property, constructing
/// the required ItemsPerRow elements on the grid which this property is attached to.
/// </summary>
private static void OnItemsPerRowPropertyChanged(DependencyObject d,
                    DependencyPropertyChangedEventArgs e)
{
  Grid grid = d as Grid;
  int itemsPerRow = (int)e.NewValue;
 
  // construct the required row definitions
  grid.LayoutUpdated += (s, e2) =>
    {
      var childCount = grid.Children.Count;
 
      // add the required number of row definitions
      int rowsToAdd = (childCount - grid.RowDefinitions.Count) / itemsPerRow;
      for (int row = 0; row < rowsToAdd; row++)
      {
        grid.RowDefinitions.Add(new RowDefinition());
      }
 
      // set the row property for each chid
      for (int i = 0; i < childCount; i++)
      {
        var child = grid.Children[i] as FrameworkElement;
        Grid.SetRow(child, i / itemsPerRow);
      }
    };
}

Note the use of a lambda expression for the event handler in order to ‘capture’ a reference to the Grid (as described in my previous blog post on binding the ScrollViewers offset properties).

Changing our markup to use the above attached property:

<ItemsControl ItemsSource="{Binding}">  
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <!-- use the ItemsPerRow attached property to dynamically add rows -->
      <Grid local:GridUtils.ItemsPerRow="1"
          ShowGridLines="True"/>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding}"/>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

The array of strings bound in code-behind results in the following grid layout being rendered:

Great, all fixed. Time to grab a coffee.

Unfortunately it isn’t that simple. The above example has a single item per grid row, typically you would want to have multiple items in each row, with each item positioned in a different column. This is where it gets tricky. DataTemplate only supports a single child element, so we will have to wrap the elements which we want to add into our grid in a panel of some sort. However, if we do this, the column index that we apply to the element of each row will be ignored because the Grid only honours the Row and Column properties of its direct descendants.

Creating a Row Template

In order to circumnavigate this issue, I have created a ‘phantom’ panel, which hosts the elements that are added to each grid row. When a phantom panel is added to the grid, its children are removed and added to the grid and the phantom is destroyed.

public class PhantomPanel : Panel
{
 
}

The property changed handler shown above is extended to remove this phantom:

private static void OnItemsPerRowPropertyChanged(DependencyObject d,
                    DependencyPropertyChangedEventArgs e)
{
  Grid grid = d as Grid;
  int itemsPerRow = (int)e.NewValue;
 
  // construct the required row definitions
  grid.LayoutUpdated += (s, e2) =>
    {
      // iterate over any new content presenters (i.e. instances of our DataTemplate)
      // that have been added to the grid
      var presenters = grid.Children.OfType<ContentPresenter>().ToList();
      foreach (var presenter in presenters)
      {
        // the child of each DataTemplate should be our 'phantom' panel
        var phantom = VisualTreeHelper.GetChild(presenter, 0) as PhantomPanel;
        if (phantom != null)
        {
 
          // remove each of the children of the phantom and add to the grid
          foreach (FrameworkElement child in phantom.Children.ToList())
          {
            phantom.Children.Remove(child);
            grid.Children.Add(child);
            // ensure the child maintains its original datacontext
            child.DataContext = phantom.DataContext;
          }
 
          // remove the presenter (and phantom)
          grid.Children.Remove(presenter);
        }
      }
 
      var childCount = grid.Children.Count;
      int rowDifference = (childCount / itemsPerRow) - grid.RowDefinitions.Count;
 
      // if new items have been added, create the required grid rows
      // and assign the row index to each child
      if (rowDifference != 0)
      {
        grid.RowDefinitions.Clear();
        for (int row = 0; row < (childCount / itemsPerRow); row++)
        {
          grid.RowDefinitions.Add(new RowDefinition());
        }
 
        // set the row property for each chid
        for (int i = 0; i < childCount; i++)
        {
          var child = grid.Children[i] as FrameworkElement;
          Grid.SetRow(child, i / itemsPerRow);
        }
      }
    };
}

The above code is pretty straightforward, however there is one subtlety, we must ensure that the DataContext of each child element is set to the DataContext that the ItemsControl assigned to each PhantomPanel, i.e. the individual items that are bound to the Grid.

With the above code it is now possible to create a more complex grid layout:

<StackPanel Orientation="Vertical">
 
  <sdk:DataGrid ItemsSource="{Binding}" Margin="10"/>
 
  <Border x:Name="LayoutRoot" Background="White"
        BorderBrush="Black" BorderThickness="1" Margin="10">
 
    <ItemsControl ItemsSource="{Binding}">
      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <Grid local:GridUtils.ItemsPerRow="2">
            <Grid.ColumnDefinitions>
              <ColumnDefinition/>
              <ColumnDefinition/>
            </Grid.ColumnDefinitions>
          </Grid>
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <!-- the row ‘template’ within a phantom panel -->
          <local:PhantomPanel>
            <TextBlock Text="{Binding Path=Item}"/>
            <TextBlock Text="{Binding Path=Quantity}" Grid.Column="1"/>
          </local:PhantomPanel>
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>
 
  </Border>
 
</StackPanel>

The above XAML renders a list of simple model objects that implement INotifyPropertyChanged in a DataGrid and an ItemsControl (using our Grid layout). Notice that if you edit the properties of the bound objects via the DataGrid, these changes are reflected in the Grid below, i.e. it is all working!

Handling CollectionChanged Events

The above example looks pretty complete, however there is one remaining issue, handling changes to the bound collection. The problem with the above solution is that it effectively subverts the ItemsControls usage of the ItemsPanel. The ItemsControl will expect that items that it adds to the Panel to appear at certain indices, by removing our phantom panels and adding their contente directly this is no longer the case.

A simple hack (and yes, it really is a hack!) is to confuse the ItemsControl into thinking that any change to our bound collection is a reset, i.e. the collection has changed completely, so the UI needs to be rebuilt from scratch. To do this, I have created an attached ItemsSource property that adapts the bound collection, ensuring that any collection changes result in the ItemsControl rebuilding its UI. The changed handler for this attached property is given below:

/// <summary>
/// Handles property changed event for the ItemsSource property.
/// </summary>
private static void OnItemsSourcePropertyChanged(DependencyObject d,
  DependencyPropertyChangedEventArgs e)
{
  ItemsControl control = d as ItemsControl;
 
  // set the ItemsSource of the ItemsControl that this property is attached to
  control.ItemsSource = e.NewValue as IEnumerable;
 
  INotifyCollectionChanged notifyCollection = e.NewValue as INotifyCollectionChanged;
  if (notifyCollection != null)
  {
    // if a collection changed event occurs, reset the ItemsControl's
    // ItemsSource, rebuilding the UI 
    notifyCollection.CollectionChanged += (s, e2) =>
      {
        control.ItemsSource = null;
        control.ItemsSource = e.NewValue as IEnumerable;
      };
  }
}

The above attached property is used in exactly the same way as the ItemsControl.ItemsSource property which it adapts. The XAML below shows how the above attached property can be used in place of the ItemsControl property:

<ItemsControl local:GridUtils.ItemsSource="{Binding}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <Grid local:GridUtils.ItemsPerRow="3">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="2*"/>
          <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
      </Grid>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <local:PhantomPanel>
        <TextBlock Text="{Binding Path=Item}"/>
        <TextBlock Text="{Binding Path=Quantity}" Grid.Column="1"/>
        <Line Stroke="LightGray" StrokeThickness="1"
              VerticalAlignment="Bottom"
              X1="0" X2="1" Y1="0" Y2="0"
              Stretch="Fill"
              Grid.ColumnSpan="2"/>
      </local:PhantomPanel>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

And here it is with a DataGrid bound to the same data:

You can add, remove and update the bound objects and the Grid rendered via the ItemsControl remains synchronised with the bound data.

Conclusions

Finally, the ItemsControl and Grid can be used together, a cause for much rejoicing! I must admit, I am pretty pleased with my solution; however, it is far from perfect. There are a couple of areas of this implementation that you should be wary of.

Firstly, the use of the LayoutUpdated event which we use to determine when items are added to our Grid. This event gets fired when anything changes in our visual tree’s layout. It has the potential to be called a lot, which is why I am always careful to check conditions and exit this method as quickly as possible if the UI is not in the state I am interested in.

Secondly, adapting the ItemsSource to force a Reset whenever an items is added or removed is pretty costly!

If you do not use the technique for rendering large quantities of data it will probably be just fine. It may be fine for large volumes of data also, however, it is always better to be aware of potential issue.

If anyone has any ideas on how to improve on this technique, please leave a comment below:

You can download the full project sourcecode: ItemsControlGrid.zip

Regards, Colin E.

Silverlight MultiBinding updated, adding support for ElementName and TwoWay binding

August 12th, 2010

This blog post describes an update to the Silverlight 4 MultiBinding technique I blogged about a couple of months ago to add support for ElementName binding and TwoWay binding.

A few months ago I posted an update to my MultiBinding solution for Silverlight 4. This technique allows you to perform the same kind of multibindings which are possible in WPF, where a property value is bound to multiple sources via a special value converter that implements the IMultiValueConverter interface, which describes how these values are combined. This update proved popular once again, and I received a few requests to add support for ElementName and TwoWay binding. I like challenge! This blog post describes how these two features were implemented, but if you just want to grab the code, you will find the link at the end of this article.

A brief recap

Before I go into the implementation details for the new features I will provide a brief recap of how my multibinding solution works. The XAML for creating a multibinding looks like the following:

<TextBlock Foreground="White" 
  <local:BindingUtil.MultiBindings>
    <local:MultiBindings>
      <local:MultiBinding TargetProperty="Text"
                          Converter="{StaticResource TitleConverter}">
        <local:BindingCollection>
          <Binding Path="Surname"/>
          <Binding Path="Forename"/>
        </local:BindingCollection>
      </local:MultiBinding>
      <local:MultiBinding TargetProperty="ToolTipService.ToolTip"
                          Converter="{StaticResource TitleConverter}">
        <local:BindingCollection>
          <Binding Path="Surname"/>
          <Binding Path="Forename"/>
        </local:BindingCollection>
      </local:MultiBinding>
    </local:MultiBindings>
  </local:BindingUtil.MultiBindings>
</TextBlock>

Here the Text property and attached ToolTip property of the TextBlock are bound to both the Surname and Forename property of the business object which is set as the DataContext of our view.

The value converter is as follows:

public class TitleConverter : IMultiValueConverter
{
 
  public object Convert(object[] values, Type targetType,
    object parameter, CultureInfo culture)
  {
    string forename = values[0] as string;
    string surname = values[1] as string;
 
    return string.Format("{0}, {1}", surname, forename);
  }
 
  ...
}

In the example below you can see that as you change the forename or surname, the title text and tooltip are updated by the multibinding.

So how does this work?

When a multibinding is created and added to an element via the BindingUtil.MultiBindings attached property, the MultiBinding instance is added to a virtual-branch, this is a branch of the visual tree that obtains the DataContext of the element to which it is bound, but is not added to the visual tree itself. The MultiBinding then creates a BindingSlave instance for each of the given Bindings. These ‘slave’ elements inherit the MultiBinding DataContext and are used to evaluate each of the individual Bindings. The MultiBinding instance aggregate the results of each binding with the IMultiValueConverter used to compute the ConvertedValue property which is bound to the target property on the element to which this MultiBinding as attached.

ElementName binding

So why does the above solution not work if one of the multibindings uses ElementName to locate the source rather than using the inherited DataContext? The problem here is that the MultiBinding and its BindingSlave instances are located in a virtual branch and are therefore not in the same namescope as the target element. As a result, they cannot perform look up of named elements.

In order to solve this problem I created a BindingSlave subclass specifically for ElementName binding. This slave locates the source element named via the ElementName property and sets it as the Source of the binding it uses to compute its Value property.

The only minor complication I encountered is that the MultiBinding might be constructed before the element referenced via ElementName. For this reason the binding slave must handle LayoutUpdated events to ensure that the named element is located if it is constructed after the multibinding.

public class ElementNameBindingSlave : BindingSlave
{
  private FrameworkElement _multiBindingTarget;
 
  /// <summary>
  /// The source element named in the ElementName binding
  /// </summary>
  private FrameworkElement _elementNameSource;
 
  private Binding _binding;
 
  public ElementNameBindingSlave(FrameworkElement target, Binding binding)
  {
    _multiBindingTarget = target;
    _binding = binding;
 
    // try to locate the named element
    ResolveElementNameBinding();
 
    _multiBindingTarget.LayoutUpdated += MultiBindingTarget_LayoutUpdated;
  }
 
  /// <summary>
  /// Try to locate the named element. If the element can be located, create the required
  /// binding.
  /// </summary>
  private void ResolveElementNameBinding()
  {
    _elementNameSource = _multiBindingTarget.FindName(_binding.ElementName) as FrameworkElement;
    if (_elementNameSource != null)
    {
      SetBinding(BindingSlave.ValueProperty, new Binding()
      {
        Source = _elementNameSource,
        Path = _binding.Path,
        Converter = _binding.Converter,
        ConverterParameter = _binding.ConverterParameter
      });
    }
  }
 
  private void MultiBindingTarget_LayoutUpdated(object sender, EventArgs e)
  {
    // try to locate the named element 
    ResolveElementNameBinding();
  }
}

The example below demonstrates element name binding by binding the Value of two Slider elements to a TextBlock which displays the sum of the two values.

<TextBlock Grid.Column="1">
  <local:BindingUtil.MultiBindings>
    <local:MultiBindings>
      <local:MultiBinding TargetProperty="Text"
                          Converter="{StaticResource SliderValueConverter}">
        <local:BindingCollection>
          <Binding ElementName="sliderOne" Path="Value"/>
          <Binding ElementName="sliderTwo" Path="Value"/>
        </local:BindingCollection>
      </local:MultiBinding>
    </local:MultiBindings>
  </local:BindingUtil.MultiBindings>
</TextBlock>
 
<Slider x:Name="sliderOne" Value="10"/>
 
<Slider x:Name="sliderTwo"  Value="20"/>

Here is the value converter that is used to compute the sum:

public class SliderValueConverter : IMultiValueConverter
{
 
  public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    if (values.Length != 2 ||
        values[0] == null ||
        values[1] == null)
      return null;
 
    return (double)values[0] + (double)values[1];
  }
 
  ...
}

You could of course use element name binding to combine the surname / forename in the first example in this blog post, but in this context it is more likely that you will want to back your UI with a business object. It is also possible to mix element name and regular (i.e. Source=DataContext) binding.

I find multibindings which use ElementName references most useful when creating complex UI layouts that do not lend themselves to being implemented using Panels. For a good example see my article on the implementation of a BulletGraph control which makes extensive use of this technique in order that the layout of the control is performed entirely within XAML.

TwoWay Binding

A two-way multibinding must be able to handle updates to the combined value and split it up into its constituent parts in order to update the multiple source bindings. In the first example where a forename and surname property are combined into a “surname, forename” string it is possible to convert back the other way, but in the example above where the values of two Sliders are combined a reverse conversion is not possible.

Modifying this multibinding solution to permit two way binding was relatively straightforward. A property changed event handler was added to the MultiBindig.ConverterValue (which is bound to the multi binding target) so that we can determine when changes have been made. This handler then uses the IMultiValueConverter to convert the value into the multiple source properties and updates the binding slaves accordingly:

/// <summary>
/// Handles property changes for the ConvertedValue property
/// </summary>
private void OnConvertedValuePropertyChanged()
{
    OnPropertyChanged("ConvertedValue");
 
    // if the value is being updated, but not due to one of the multibindings
    // then the target property has changed.
    if (!_updatingConvertedValue)
    {
      // convert back
      object[] convertedValues = Converter.ConvertBack(ConvertedValue, null,
          ConverterParameter, CultureInfo.InvariantCulture);
 
      // update all the binding slaves
      if (Children.Count == convertedValues.Length)
      {
        for (int index = 0; index < convertedValues.Length; index++)
        {
          ((BindingSlave)Children[index]).Value = convertedValues[index];
        }
      }
    }
}

In order to use two way multibinding both the multibinding mode and the bindings within the BindingCollection must be set to TwoWay. See the example given below:

<TextBlock Text="Surname:"/>
<TextBox  Grid.Column="1" Text="{Binding Path=Surname, Mode=TwoWay}"/>
 
<TextBlock Grid.Row="1" Text="Forename:"/>
<TextBox Grid.Row="1"  Grid.Column="1" Text="{Binding Path=Forename, Mode=TwoWay}"/>
 
<TextBlock Grid.Row="2" Text="Combined:"/>
<TextBox Grid.Row="2"  Grid.Column="1" >
  <local:BindingUtil.MultiBindings>
    <local:MultiBindings>
      <local:MultiBinding TargetProperty="Text"
                        Converter="{StaticResource TitleConverter}"
                        Mode="TwoWay">
        <local:BindingCollection>
          <Binding Path="Surname" Mode="TwoWay"/>
          <Binding Path="Forename" Mode="TwoWay"/>
        </local:BindingCollection>
      </local:MultiBinding>
    </local:MultiBindings>
  </local:BindingUtil.MultiBindings>
</TextBox>

You can have try of two way multibinding below where the values of the forename and surname text boxes are combined in the box below. However, you ca also make updates to the combined result which will then be converted back into its constituent parts:

And here is the value converter:

public class TitleConverter : IMultiValueConverter
{
  #region IMultiValueConverter Members
 
  public object Convert(object[] values, Type targetType,
    object parameter, System.Globalization.CultureInfo culture)
  {
    string forename = values[0] as string;
    string surname = values[1] as string;
 
    return string.Format("{0}, {1}", surname, forename);
  }
 
  public object[] ConvertBack(object value, Type[] targetTypes,
    object parameter, System.Globalization.CultureInfo culture)
  {
    string source = value as string;
    var pos = source.IndexOf(", ");
 
    string forename = source.Substring(pos + 2);
    string surname = source.Substring(0, pos);
 
    return new object[] { forename, surname };
  }
 
  #endregion
}

So, there you have it, two-way and element name multibinding :-)

You can download the full source, including a WPF build (thanks to Stefan Olson) here: SLMultiBindingUpdated.zip

Now … go forth and multibind.

Regards, Colin E.