Colin Eberhardt's Technology Adventures

Binding a Silverlight 3 DataGrid to dynamic data via IDictionary (Updated)

March 26th, 2010

In this post I demonstrate a method for binding a Silverlight 3 DataGrid to dynamic data, i.e. data which does not have properties that are known at design time. This technique results in a bound grid which is sortable and editable. This blog post is a bug fix (due to differences between SL2 and SL3) and expansion on my previous posts on this subject.

WinForms, WPF and ASP.NET are all perfectly capable of binding to dynamic data via a DataGrid, or custom TypeDescriptors. However Silverlight has neither of these features. Around one year ago I published a pair of articles that demonstrated a technique that could be used to bind a DataGrid to dynamic data presented as a list of dictionaries. The first article detailed how to use a ValueConverter to access the cell values within a dictionary and how a custom CollectionView could be created to permit sorting. The second article showed how to extend this solution to enable editing within the grid.

These two blog posts have proven very popular, with 84 comments between them :-) . However I have seen a recurring theme in the comments to these posts which I will now address:

  1. SL3 Sorting – I have had a number of reports that indicate sorting is broken in Silverlight 3
  2. SL3 Editing – It looks like editing is also broken in SL3 :-(
  3. Adding columns in code behind – My examples configured columns in XAML, but for truly dynamic data this would have to be done in code-behind. A number of readers have had difficulty with converting the XAML into the required C# code.

This blog post will address these specific issues, providing a solution that works for SL3. If you are interested in the technical solution you might want to read the first and second blog posts before you read this one. The solution for SL3 is essentially the same, it is just a few subtle differences in the DataGrid that cause these issues.

Starting with the first of the SL3 problems, sorting. The DataGrid uses the SortDescriptions property of our collection which implements ICollectionView in order to sort the data. This remains unchanged in SL3. However, the ICollectionView implementation that I presented in the previous blog post did not implement all the methods on this interface, leaving out the ones that the SL2 DataGrid does not use.

When the SL3 DataGrid performs a sort or group operation, it first calls the DeferRefresh method on ICollectionView. This is quite a neat little method; what it does is allow you to suppress the events that the collection would typically raise whilst you make a number of changes, for example, applying a sort then a grouping, then raises a single collection changed event. This results in much less work being performed by the UI as it now handles a single event rather than multiple events. You can find a good example of how this works on Matt Manela’s blog. DeferRefresh is implemented by returning in IDisposable object, the implementation is quite trivial:

public class SortableCollectionDeferRefresh : IDisposable
{
    private readonly SortableCollectionView _collectionView;
 
    internal SortableCollectionDeferRefresh(SortableCollectionView collectionView)
    {
        _collectionView = collectionView;
    }
 
    public void Dispose()
    {
        // refresh the collection when disposed.
        _collectionView.Refresh();
    }
}

It is used by our collection as follows:

public class SortableCollectionView : ObservableCollection<Row>, ICollectionView
{
  ...
  public IDisposable DeferRefresh()
  {
      return new SortableCollectionDeferRefresh(this);
  }
  ...
}

That solves the sorting issue :-)

The lack of editing issue was a but odd, someone on the Silverlight forums indicated that they think this is an undocumented breaking change. With a SL3 DataGrid if you bind to a property of type object, the column becomes read-only, even if the DataGrid itself is not read-only. The solution is simply to set the IsReadOnly of each column to false.

With these few changes we now how a fully functioning DataGrid bound to our dynamic data:

The final recurring question to my previous blog posts is how to create the bound DataGrid columns in code-behind. To illustrate how this is done I will create an example where the DataGrid is bound to some XML that sits in a TextBox underneath the grid.

The example looks like this:

The two buttons in the centre allow you to synchronise the DataGrid and the XML, one formats the current grid contents in XML, the other takes the XML and dynamically binds the contents to the grid. You can try editing the data, then updating the XML and vice-versa. You can even add new columns to the XML data (hopefully the XML structure is pretty self explanatory – there is no error checking so take care ;-) ). The DataGrid is of course editable and sortable.

The interesting part of the code is the method that takes the XML contents and binds it to the grid. It is as follows:

/// <summary>
/// Copies the XML contents of the textbox into the DataGrid
/// </summary>
private void XmlToGrid()
{
  // clear the grid
  _dataGrid.ItemsSource = null;
  _dataGrid.Columns.Clear();
 
  // grab the xml into a XDocument
  XDocument xmlDoc = XDocument.Parse(_xmlInput.Text);
 
  // find the columns
  List<string> columnNames = xmlDoc.Descendants("column")
                                   .Attributes("name")
                                   .Select(a => a.Value)
                                   .ToList();
 
  // add them to the grid
  foreach (string columnName in columnNames)
  {
    _dataGrid.Columns.Add(CreateColumn(columnName));
  }
 
  SortableCollectionView data = new SortableCollectionView();
 
  // add the rows
  var rows = xmlDoc.Descendants("row");
  foreach (var row in rows)
  {
    Row rowData = new Row();
    int index = 0;
    var cells = row.Descendants("cell");
    foreach(var cell in cells)
    {
      rowData[columnNames[index]] = cell.Value;
      index++;
    }
    data.Add(rowData);
  }
 
  _dataGrid.ItemsSource = data;
}

The above code clears the grid, then uses a bit of Linq to XML to query the XML within the TextBox, creating the SortableCollectionView and Row instances which are the data objects for our dynamic data as described in the previous blog posts. The columns are created in code behind as follows:

private RowIndexConverter _rowIndexConverter = new RowIndexConverter();
 
private DataGridColumn CreateColumn(string property)
{
  return new DataGridTextColumn()
  {
    CanUserSort = true,
    Header = property,
    SortMemberPath = property,
    IsReadOnly = false,
    Binding = new Binding("Data")
    {
      Converter = _rowIndexConverter,
      ConverterParameter = property
    }
  };
}

This is really no different to the technique that you use when creating the column definitions in XAML. There is nothing special about XAML, it is essentially just an XML markup for creating objects.

Hopefully this blog post will help answer the recurring questions, and reduce the number of “it doesn’t work in SL3″ mails I get. Perhaps I will just get 84 “Thank you” comments instead :-)

You can download the full sourcecode for this blog post: SilverlightTable.zip

Regards, Colin E.

Binding a Silverlight DataGrid to dynamic data Part 2 – editable data and INotifyPropertyChanged

April 22nd, 2009

UPDATE: This blog post was written with a SL2 DataGrid, for SL3, please see my updated blog post.

In my previous blog post I described a method for solving the commonly faced problem of binding a Silverlight DataGrid to dynamic data, the form of which is not know at compile time. This blog post extends on the method previously described, adding change notification, allowing the DataGrid to synchronise the UI with changes to the bound data and to allow the user to edit the DataGrid’s contents.

To briefly recap my previous post, the dynamic data is copied to a collection of Rows:

public class Row
{
  private Dictionary<string, object> _data = new Dictionary<string, object>();
 
  public object this [string index]
  {
    get { return _data[index]; }
    set { _data[index] = value; }
  }
}

Where the row ‘properties’ which are implemented via the string indexer bound to the grid via a ValueConverter. The XAML for the DataGrid looks like the following:

<data:DataGrid Name="_dataGrid" AutoGenerateColumns="False"  IsReadOnly="False" Margin="5">
    <data:DataGrid.Columns>
        <data:DataGridTextColumn Header="Forename"
                                 Binding="{Binding Converter={StaticResource RowIndexConverter},
                                    ConverterParameter=Forename}"/>
        <data:DataGridTextColumn Header="Surname" 
                                 Binding="{Binding Converter={StaticResource RowIndexConverter},
                                    ConverterParameter=Surname}"/>
        ...               
    </data:DataGrid.Columns>
</data:DataGrid>

Where the ValueConverter takes the ConverterParameter and uses it to index the bound Row instance:

public class RowIndexConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    Row row = value as Row;
    string index = parameter as string;
    return row[index];
  } 
}

It is important to note that the Binding does not have a Path defined. As a result, the binding source is the Row instance itself rather than a property of the Row as would more normally be the case when binding data. The rest of the post described how to create a collection view which sorts the collection via the Row’s string indexer. You can read about this in full in my previous blog post.

Now, one question a few people have asked me is how to implement INotifyPropertyChanged on the Row class in order to make the DataGrid editable. Simply implementing INotifyPropertyChanged on the Row class, with events raised from the index setter, will not make the grid editable or synchronised with the bound data. The underlying problem here is that the Binding does not have a Path specified, therefore, the binding framework does not know which property name to look out for when handling PropertyChanged events. Interestingly I would expect the above bindings to be updated if a PropertyChanged event were raised with a null or empty PropertyName string, however they do not.

So if the Binding framework needs a Path for the binding in order for change notification to work, we will have to fabricate one for this purpose! We can modify the Row class as follows, adding a Data property which is simply a reference to the Row instance itself:

public class Row : INotifyPropertyChanged
{
    private Dictionary<string, object> _data = new Dictionary<string, object>();
 
    public object this [string index]
    {
        get
        {
            return _data[index];
        }
        set
        {
            _data[index] = value;
 
            OnPropertyChanged("Data");
        }
    }
 
    public object Data
    {
        get
        {
            return this;
        }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    protected void OnPropertyChanged(string property)
    {
        if (PropertyChanged!=null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
}

In order to bind this class we modify our bindings so that the source Path points to the Data property:

...
<data:DataGridTextColumn Header="Forename"
                           Binding="{Binding Path=Data, Converter={StaticResource RowIndexConverter},
                           ConverterParameter=Forename}"/>
<data:DataGridTextColumn Header="Forename"
                           Binding="{Binding Path=Data, Converter={StaticResource RowIndexConverter},
                           ConverterParameter=Surname}"/>
...

With this change in place, all of our bindings are bound to the Row’s Data property. Again, the Row’s indexer is being accessed via our value converter. However, if any ‘property’ change via the string indexer setter will result in all of our bindings being updated for that Row. I know, it is not the most efficient solution – but at least it work!

The next problem is making the DataGrid editable. The problem we face here is that all of our bindings are to the same property, Data. When a cell is edited, the binding framework will quite happily call the Data properties setter, with the updated value. However, how do we know which property of the Row was really being set? The only place we hold this information is in the ConverterParameter which is fed to our RowIndexConverter value converter. Fortunately, there is a solution to this problem, when the binding framework updates the bound object, it will first invoke the ConvertBack method on our value converter. This gives us the opportunity to ‘capture’ the converter parameter and feed it into the setter of our Data property, as shown below:

public class RowIndexConverter : IValueConverter
{
    ...
 
    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        return new PropertyValueChange(parameter as string, value);
    }
}

Where PropertyValueChanged is a simple value object:

public class PropertyValueChange
{
    private string _propertyName;
    private object _value;
 
    public object Value
    {
        get { return _value; }
    }
 
    public string PropertyName
    {
        get { return _propertyName; }
    }
 
    public PropertyValueChange(string propertyName, object value)
    {
        _propertyName = propertyName;
        _value = value;
    }
}

The setter for the Data property will now be invoked with an instance of PropertyValueChanged, giving it all the information it requires to invoke the string indexer with the correct ‘property’ name:

public class Row : INotifyPropertyChanged
{
    ...
 
    public object Data
    {
        get { return this; }
        set
        {
            PropertyValueChange setter = value as PropertyValueChange;
            _data[setter.PropertyName] = setter.Value;
        }
    }
    ...
}

With this change in place, we the user is able to edit the data bound to the DataGrid, and the binding ensures that the DataGrid UI is synchronised with any changes to the bound data that may happen elsewhere in our code.

One final thought that struck me is that this technique uses the Binding’s associated ValueConverter to access the Row’s string indexer, but what if we wanted to use a ValueConverter for something else like formatting? Fortunately it is a pretty straightforward process to nest one value converter inside another. For details, see the attached project. For now, have quick play with the grid below, where all the columns are editable and the button click event sets the Row’s Age property demonstrating how the DataGrid is synchronised:

private void Button_Click(object sender, RoutedEventArgs e)
{
    // demonstrate the property changes from code-behind still work.
    Random rand = new Random();
    foreach (var row in _rows)
    {
        row["Age"] = rand.Next(10) + 5;
    }
}

Also, the Age column has a value converter associated …

So there you have it, binding to dynamic data with INotifyPropertyChanged implemented and an editable DataGrid. The only reservation I have with this technique is that I am really bending the binding framework to achieve the results, having a Data property which expects different types for the getter and setter is a little ugly … use with caution!

You can download the project sourcecode: silverlightdynamicbinding2.zip

Regards, Colin E.

Binding a Silverlight DataGrid to dynamic data via IDictionary

April 17th, 2009

This post demonstrates a technique for binding a Silverlight DataGrid to dynamic data, the structure of which is not know at compile-time …

UPDATE #1: I have extended this technique to add include change notification so that the DataGrid can be made editable. Read all about it in part two.

UPDATE #2: This blog post was written with a SL2 DataGrid, for SL3, please see my updated blog post.

With Silverlight binding data to a DataGrid is a very straightforward process. With an XML datasource, you can simply parse your data via Linq to SQL into an anonymous type then bind the resulting collection to the grid. Just a few simple lines of code. But, what if the data you want to bind to your grid is dynamic? That is, at compile time you do not know how many columns are required, or what their contents is. This is a common problem that Silverlight users have faced again, and again, and again and again!

The most obvious solution to this problem is to create a dictionary for each row of your DataGrid, and bind your columns to your values via the dictionary’s string indexer:

Binding="{Binding Path=[Name]}"

However, unfortunately the PropertyPath syntax used for binding does not understand indexers, making it impossible to bind to a dictionary.

Vladimir Bodurov presents an ingenious solution to this problem by dynamically generating a new Type based on the values present within the dictionary, i.e. If the dictionary contains the keys “Name” and “Age”, a Type will be generated that has properties of Name and Age. Crazy stuff! Here I would like to show an alternative method that does not use intermediate Language or other black magic!

We will start with a simple example of a class which can be used to store ‘dynamic’ data for rendering in our DataGrid:

public class Row
{
  private Dictionary<string, object> _data = new Dictionary<string, object>();
  public object this [string index]
  {
    get { return _data[index]; }
    set { _data[index] = value; }
  }
}

We can populate a collection of these objects and associate them with a DataGrid as follows:

Random rand = new Random();
 
var rows = new ObservableCollection<Row>();
for (int i = 0; i < 200; i++)
{
  Row row = new Row();
  row["Forename"] = s_names[rand.Next(s_names.Length)];
  row["Surname"] = s_surnames[rand.Next(s_surnames.Length)];
  row["Age"] = rand.Next(40) + 10;
  row["Shoesize"] = rand.Next(10) + 5;
  rows.Add(row);
}
 
_dataGrid.ItemsSource = rows;

However, as mentioned earlier, we cannot create a binding path that accesses our Rows indexer, so just how do we bind the columns to our data?

The classic .NET solution to this problem would be to create a custom property descriptor. When databinding, the properties of an object are not accessed directly, rather they are accessed via their associated property descriptor. A custom property descriptor can be supplied for our Row class, via the ICustomTypeDescriptor interface for example, that exposes properties which when accessed invoke our indexer. This is how the .NET DataRowView exposes its properties. Unfortunately there is one small snag here … Silverlight does not include the required interfaces to create custom properties.

A simple workaround to this problem is to use a binding that binds each row directly to each Row item rather than a specific property of the item, then use a value converter to access the indexer and extract the required value. Here is an example:

<data:DataGrid Name="_dataGrid" AutoGenerateColumns="False" Height="300" IsReadOnly="False">
  <data:DataGrid.Columns>
    <data:DataGridTextColumn Header="Forename" Binding="{Binding Converter={StaticResource RowIndexConverter}, ConverterParameter=Forename}"/> 
    <data:DataGridTextColumn Header="Surname" Binding="{Binding Converter={StaticResource RowIndexConverter}, ConverterParameter=Surname}"/> 
    <data:DataGridTextColumn Header="Age" Binding="{Binding Converter={StaticResource RowIndexConverter}, ConverterParameter=Age}"/> 
    <data:DataGridTextColumn Header="Shoesize" Binding="{Binding Converter={StaticResource RowIndexConverter}, ConverterParameter=Shoesize}"/> 
  </data:DataGrid.Columns>
</data:DataGrid>

And here is the value converter:

public class RowIndexConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    Row row = value as Row;
    string index = parameter as string;
    return row[index];
  }
 
  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
    throw new NotImplementedException();
  }
}

In the above XAML, the binding expression does not have a Path specified, therefore, the binding source is our Row instance rather than a property of the Row. The RowIndexConverter value converter simply uses the supplied ConverterParameter for each column to access the Row indexer and extract the correct value. This works quite nicely, and we are able to see our data within the grid:

grid

However, there is one problem here, if you click on the column headers the grid does not sort the data. The columns of a DataGrid have CanUserSort and SortMemberPath properties, however setting these will not help because the DataGrid will expect the bound object to have a property with the given name which of course it does not! To solve this problem (without resorting to dynamically generated types) we need to delve a little deeper into the way in which the DataGrid binds to the data.

A lot of insight can be gained from the documentation of ICollectionView:

The DataGrid control uses this interface to access the indicated functionality in the data source assigned to its ItemsSource property. If the ItemsSource implements IList, but does not implement ICollectionView, the DataGrid wraps the ItemsSource in an internal ICollectionView implementation.

The ICollectionView interface is responsible for filtering, sorting and grouping of the data bound to the DataGrid. WPF also has the ICollectionViewinterface, you can read a good overview of its features on Marlon Grech’s blog. However, whereas WPF wraps the DataContext itself in a view which is shared across multiple controls, it would appear that Silverlight restricts its usage to the DataGrid. This causes problems if, for example, you want to synchronize the current item between controls (However, Laurent Bugnion has a novel solution for emulating this behaviour).

So, it is the ICollectionView which is responsible for sorting our data. The internal implementation of this interface which the DataGrid creates will expects our object to expose the bound properties, which explains why it does not work. However, if we supply our own ICollectionView interface, we can take control of sorting and implement it ourselves, accessing our ‘property’ values via the Row’s string indexer.

The ICollectionView interface has a lot of methods, events and properties, fortunately I was able to find a suitable implementation of this interface on Manish Dalal’s blog. He had implemented this interface, on a class which extends ObservableCollection, in order to bind a DataGrid to a collection where the data from the server is being paged, hence sorting must be done server side. This gives us pretty much everything we need here, a collection class which is able to manage sorting itself. The only change required is to the ICollectiomView.Refresh() method which is responsible for refreshing the view after the SortDescriptions have changed.

The implementation of this method is as follows:

public class SortableCollectionView : ObservableCollection<Row>, ICollectionView
{
 
  ...
  public void Refresh()
  {
      IEnumerable<Row> rows = this;
      IOrderedEnumerable<Row> orderedRows = null;
 
      // use the OrderBy and ThenBy LINQ extension methods to
      // sort our data
      bool firstSort = true;
      for (int sortIndex = 0; sortIndex < _sort.Count; sortIndex++)
      {
          SortDescription sort = _sort[sortIndex];
          Func<Row, object> function = row => row[sort.PropertyName];
          if (firstSort)
          {
              orderedRows = sort.Direction == ListSortDirection.Ascending ?
                  rows.OrderBy(function) : rows.OrderByDescending(function);
 
              firstSort = false;
          }
          else
          {
              orderedRows = sort.Direction == ListSortDirection.Ascending ?
                  orderedRows.ThenBy(function) : orderedRows.ThenByDescending(function);
          }
      }
 
      _suppressCollectionChanged = true;
 
      // re-order this collection based on the result if the above
      int index = 0;
      foreach (var row in orderedRows)
      {
          this[index++] = row;
      }
 
      _suppressCollectionChanged = false;
 
      // raise the required notification
      this.OnCollectionChanged(
          new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
   }
 
  ...
}

When the user clicks on a grid view header, it modifies the bounds ICollectionView.SortDescription to reflect this change in state. The implementation of ICollectiomView from Manish’s blog invokes the Refresh method whenever the ICollectionView.SortDescription collection changes. In the above implementation we use the OrderBy and ThenBy LINQ extension methods to order the data. Interestingly, OrderBy is a method on IEnumerable, whereas ThenBy is a methods on the IOrderedEnumerable, hence the funny looking logic involving ‘firstSort’. Once the sorting has been performed, the underlying collection is re-ordered to match. The only subtle part is that we use a boolean field, _suppressCollectionChanged to suppress the numerous CollectionChanged events that would be fired by ObservableCollection during this process. Finally we raise NotifyCollectionChanged, resulting in the DataGrid updating to reflect the sort order.

Putting it all together, we simply populate our SortableCollectionView and bind this to the DataGrid, modifying the XAML to explicitly inform the grid that it can sort and which property each column sorts on (usually this is inferred from the Binding Path):

<data:DataGrid Name="_dataGrid" AutoGenerateColumns="False"  IsReadOnly="False" Margin="5">
    <data:DataGrid.Columns>
        <data:DataGridTextColumn Header="Forename" CanUserSort="True" SortMemberPath="Forename" 
                                  Binding="{Binding Converter={StaticResource RowIndexConverter},
                                    ConverterParameter=Forename}"/>
        <data:DataGridTextColumn Header="Surname" CanUserSort="True" SortMemberPath="Surname" 
                                 Binding="{Binding Converter={StaticResource RowIndexConverter},
                                    ConverterParameter=Surname}"/>
        <data:DataGridTextColumn Header="Age" CanUserSort="True" SortMemberPath="Age" 
                                 Binding="{Binding Converter={StaticResource RowIndexConverter},
                                    ConverterParameter=Age}"/>
        <data:DataGridTextColumn Header="Shoesize" CanUserSort="True" SortMemberPath="Shoesize" 
                                 Binding="{Binding Converter={StaticResource RowIndexConverter},
                                    ConverterParameter=Shoesize}"/>                
    </data:DataGrid.Columns>
</data:DataGrid>

And here it is in action:

You can download the complete solution here: silverlightdynamicbinding.zip.

Regards,
Colin E.

Styling hard-to-reach elements in control templates with attached behaviours

February 10th, 2009

OK, the title of this blog post is not very snappy, but it is not an easy problem to describe in a few short words. Here’s the rub, the WPF DataGrid has a select-all button located in the top-left corner, just like Excel and many other grid controls / applications. However, with the default style, this button is barely visible and I would not be surprised if a user of the grid failed to see it.

select-all

Unfortunately restyling this button is not all that straightforward. The more complex WPF controls like the DataGrid and ListView typically expose the template used to construct, and the style applied to their various visual elements.  However, the DataGrid does not expose a style or template for the select-all button.

Fortunately, all is not lost. With WPF, if a control does not expose a style for one of its component parts, you can replicate and replace its entire template. Sometimes this approach feels a little heavy-handed … “I can’t seem to find a way to fit those flashy alloy wheels to my car, so I’ll just by a new car that already has the wheels I like”.

I want to explore a more lightweight approach.

Whilst it is usually preferable to modify a controls template from XAML, in cases like this, I prefer the more concise approach of modifying them in code-behind. In order to do this, you need to handle the FrameworkElement.Loaded event on the control whos template you wish to modify. This event is fired after the control’s visual tree has been constructed, to verify this add a breakpoint in the event handler and inspect the visual tree with Mole. The image below shows the visual tree of my DataGrid which I have expanded to locate the select-all button.

datagrid-mole

You can see that the button is the first element, four steps down the visual tree, therefore it should be easy to locate by walking the visual tree. Once it has been reached we can simply replace its template to the one which we desire:

private void Grid_Loaded(object sender, RoutedEventArgs e)
{
    DependencyObject dep = sender as DependencyObject;
 
    // Navigate down the visual tree to the button
    while (!(dep is Button))
    {
        dep = VisualTreeHelper.GetChild(dep, 0);
    }
    Button button = dep as Button;
 
    // apply our new template
    object res = FindResource("SelectAllButtonTemplate");
    button.Template = res as ControlTemplate
}

The template SelectAllButtonTemplate is simply defined as a resource of our Window.

This works just fine for our single grid, but what if we want to use the same trick on multiple DataGrids? (Besides, we have code-behind, which in WPF is a bit of a dirty word!).

The Attached Behaviour pattern is a useful WPF pattern that proves very useful in this situation. In brief, attached properties add state to a your WPF elements, whereas attached behaviours add behaviour. When an attached property becomes associated with a dependency object, an event is raised. We can handle this event and register handlers on the events of the object being attached to, in this case, our DataGrid’s Loaded event.

The following code is our attached behaviour in its entirety:

public static class DataGridStyleBehaviour
{
    #region attached property
 
    public static ControlTemplate GetSelectAllButtonTemplate(DataGrid obj)
    {
        return (ControlTemplate)obj.GetValue(SelectAllButtonTemplateProperty);
    }
 
    public static void SetSelectAllButtonTemplate(DataGrid obj, ControlTemplate value)
    {
        obj.SetValue(SelectAllButtonTemplateProperty, value);
    }
 
    public static readonly DependencyProperty SelectAllButtonTemplateProperty =
        DependencyProperty.RegisterAttached("SelectAllButtonTemplate",
        typeof(ControlTemplate), typeof(DataGridStyleBehaviour),
        new UIPropertyMetadata(null, OnSelectAllButtonTemplateChanged));
 
    #endregion
 
    #region property behaviour
 
    // property change event handler for SelectAllButtonTemplate
    private static void OnSelectAllButtonTemplateChanged(
        DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        DataGrid grid = depObj as DataGrid;
        if (grid == null)
            return;
 
        // handle the grid's Loaded event
        grid.Loaded += new RoutedEventHandler(Grid_Loaded);
    }
 
    // Handles the DataGrid's Loaded event
    private static void Grid_Loaded(object sender, RoutedEventArgs e)
    {
        DataGrid grid = sender as DataGrid;
        DependencyObject dep = grid;
 
        // Navigate down the visual tree to the button
        while (!(dep is Button))
        {
            dep = VisualTreeHelper.GetChild(dep, 0);
        }
        Button button = dep as Button;
 
        // apply our new template
        ControlTemplate template = GetSelectAllButtonTemplate(grid);
        button.Template = template;
    }
 
    #endregion
}

This attached property can be used as illustrated below, where we apply the SelectAllButtonTemplate from our Window’s resources to a DataGrid:

<Window ...
    Title="BBC News RSS" Height="300" Width="400">
 
    <Window.Resources>
        <XmlDataProvider x:Key="NewsFeed"
                     Source="http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml"  
                     XPath="//item" />
 
        <ControlTemplate x:Key="SelectAllButtonTemplate" TargetType="{x:Type Button}">
            <Grid>
                <Rectangle  x:Name="Border"
                            Fill="Pink" 
                            SnapsToDevicePixels="True" />
                <Polygon   x:Name="Arrow"
                           HorizontalAlignment="Right"
                           VerticalAlignment="Bottom"
                           Margin="8,8,3,3"
                           Opacity="0.15"
                           Fill="Black"
                           Stretch="Uniform"
                           Points="0,10 10,10 10,0" />
            </Grid>            
        </ControlTemplate>
    </Window.Resources>
 
    <Grid>
        <dg:DataGrid Name="dataGrid" AutoGenerateColumns="False" 
                     local:DataGridStyleBehaviour.SelectAllButtonTemplate="{StaticResource SelectAllButtonTemplate}"
                     ItemsSource="{Binding Source={StaticResource NewsFeed}}" RowHeaderWidth="25">
            <dg:DataGrid.Columns>
                <dg:DataGridTextColumn Header="Title" Binding="{Binding XPath=title}" Width="*"/>
                <dg:DataGridHyperlinkColumn   Header="Url" Binding="{Binding XPath=link}" Width="*"/>
                <dg:DataGridTextColumn Header="Date" Binding="{Binding XPath=pubDate}" Width="*"/>
            </dg:DataGrid.Columns>
        </dg:DataGrid>
    </Grid>
</Window>

The result is a beautiful pink select-all button that I don’t think any user would miss in a hurry:

pinkbutton

And a clean code-behind file for our Window :-)

You can download the demo project for this blog post in the following zip file, wpfstylinghiddenelements.

One last thing … if you are implementing a WPF / Silverlight control, please expose the styles and templates for all component parts of your control!

Regards, Colin E.