2

Can someone tell me if this is possible. I have a WPF datagrid and I'd like to bind the column headers of the datagrid to properties/fields in the code behind.

So heres what I've tried. This is my column code.

<DataGridTextColumn  Header="{Binding ElementName=frmAssetPPM, Path=HeaderProperty}" 

And this is what I've added to the window xaml.

<Window .... Name="frmAssetPPM">

And this is my property definition in the code behind:

private const string HeaderPropertyConstant = "Property";
private string _headerProperty = HeaderPropertyConstant;

public string HeaderProperty 
{
    get { return _headerProperty; }
    set { _headerProperty = value; }
}

However, when I run the application, I'm getting this error message displayed in the Output window in VS.

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=HeaderProperty; DataItem=null; target element is 'DataGridTextColumn' (HashCode=47624635); target property is 'Header' (type 'Object')

Can someone tell me what I'm doing wrong? Or if I can even do this? I read somewhere that columns are a separate object and this sometimes leads to complications.

Yael
  • 1,566
  • 3
  • 18
  • 25
Andrew N
  • 502
  • 7
  • 20
  • 1
    possible duplicate of [Binding DataGrid column Header to DataContext](http://stackoverflow.com/questions/8891560/binding-datagrid-column-header-to-datacontext) – RogerN May 19 '15 at 14:49

1 Answers1

2

Some things are tough to bind because they are not part of the Visual tree, such as popups or in your case - datagrid headers. A well known workaround is to use Josh Smith's DataContextSpy. Basically you instantiate it as a resource and give it the binding. Then use that instance elsewhere, where you can tap into it's data context. There are plenty examples on the web, but to get you started, something like this should work..

<DataGrid.Resources>
    <DataContextSpy x:Key="dcSpy" 
                    DataContext="{Binding  ElementName=frmAssetPPM, Path=HeaderProperty}"/>
 ....

then your binding will work:

<DataGridTextColumn  Header="{Binding Source={StaticResource dcSpy}, Path=DataContext}" 

here's Josh Smith's code if you don't find it on the web:

public class DataContextSpy : Freezable
{
    public DataContextSpy ()
    {
        // This binding allows the spy to inherit a DataContext.
        BindingOperations.SetBinding (this, DataContextProperty, new Binding ());
    }

    public object DataContext
    {
        get { return GetValue (DataContextProperty); }
        set { SetValue (DataContextProperty, value); }
    }

    // Borrow the DataContext dependency property from FrameworkElement.
    public static readonly DependencyProperty DataContextProperty = FrameworkElement
        .DataContextProperty.AddOwner (typeof (DataContextSpy));

    protected override Freezable CreateInstanceCore ()
    {
        // We are required to override this abstract method.
        throw new NotImplementedException ();
    }
}
denis morozov
  • 6,236
  • 3
  • 30
  • 45
  • Thanks, I've tried this and its not working. I've got my Windows datacontext set to the ViewModel. Do you think that's why its not working? – Andrew N May 19 '15 at 15:36
  • ok, so then setting DataContext's DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext}" should definitely work. Unless you set the datacontext on the window after the xaml is loaded.. then it's a timing issue. – denis morozov May 19 '15 at 15:37
  • Are you sure? I can see that we're setting the datacontext of dcSpy to the datacontext of the elementname = frmAssetPPM. And in XAML I've got the windows datacontext set to the ViewModel. ` ` – Andrew N May 19 '15 at 15:39
  • Oh, wait...you property that you bind the Headers to is on the View, not the ViewModel, let me update the answer.. – denis morozov May 19 '15 at 15:44
  • Updated...try it again. Now the binding should be pulling from the View's HeaderProperty, not it's DataContext (which is your ViewModel) – denis morozov May 19 '15 at 15:46
  • Another update, sorry, when Binding the Grid column, I didn't bind the dcSpy as a StaticResouce, that's the key. That should definitely work – denis morozov May 19 '15 at 15:49
  • Sorry but this time I'm getting this error. `System.Windows.Data Error: 40 : BindingExpression path error: 'HeaderProperty' property not found on 'object' ''AssetPPM2ViewModel' (HashCode=42584487)'. BindingExpression:Path=DataContext.HeaderProperty; DataItem='DataContextSpy' (HashCode=5628376); target element is 'DataGridTextColumn' (HashCode=1680071); target property is 'Header' (type 'Object')` – Andrew N May 19 '15 at 16:01
  • So progress! Now, the good news is that the Grid Column's Header Binding is pulling from theDataContextSpy, the data context spy DataBinding is not set up correctly. It looks like it is pulling from the ViewModel not from your Window. I updated my answer where the dataContextSpy Binding was changed to use the ElementName, have you updated your code? I think that should work.. – denis morozov May 19 '15 at 16:48