Binding a WPF Grid Column Header

This is another of the occasional posts that are primarily here to remind me how I did something, and because it might be useful to somebody else!

Over recent years all of the desktop based windows applications I’ve developed have had user interfaces created using Windows Presentation Framework, having done Windows Forms extensively previously, it’s  a definite step up, with great support for data binding user interface elements to data fields. As such it is pretty straightforward to produce user interfaces with a really clear separation of concerns, using a Model-View-ViewModel design.

A recent change request for one of my projects has been to provide dynamic labelling for data fields – different sorts of users store the same data in the same fields, but use different terminology which needs to be reflected in the labelling. Whilst the WPF binding support is able to cope with labels without an issue, I hit a bit of a dead end with a large data grid that was used in the application where the column headers were required to change. Whilst the data items in the grid can be bound without problems, the column headers just wouldn’t work.

Having failed with the standard binding, I then looked at using FindAncestor to try and point the column header at the ViewModel that was mapped to the data context of the window, again this didn’t work.

After much digging around and experimenting, I eventually came upon this question on StackOverflow which while it was about binding column visibility, demonstrated the same basic problem, that you couldn’t bind column properties. The first answer by Cameron MacFarland explains why it doesn’t work, and gives a good answer that solved the problem for me. It’s not the first question that comes up when searching for the problem on Stack Overflow, but the solution offered by Cameron is a much neater and cleaner solution than many of the other solutions offered to the similar questions.

The issue is that under WPF data grid columns are not part of either the visual or logical tree, and therefore the usual relative binding mechanisms don’t work. The solution is to use a static binding, and create a proxy class in the application code that provides what would come via the relative binding.

The property is set up as follows:

<UserControl.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</UserControl.Resources>

<DataGridTemplateColumn Visibility="{Binding Data.IsVisible, 
    Source={StaticResource proxy},
    Converter={StaticResource BooleanToVisibilityConverter}}">

And then you need to create this binding proxy class:

public class BindingProxy : Freezable
{
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Data.
    // This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), 
        typeof(BindingProxy), new UIPropertyMetadata(null));
}

Although the example Cameron gives is for column visibility, once the binding proxy is set up it works just as well for other column properties such as the column header I was trying to bind.

Leave a Reply