Forwarding the DataGrid’s DataContext to its’ columns..
DataContext is a very handy inherited property on any WPF application..
Most of the time, I set DataContext near the root on the [logical] tree, and let the inherited DataContext do its magic to bind the rest of the scene.
I recently tried to bind a DataGridColumn to its inherited DataContext (via its datagrid container) and got a very surprising answer on the output trace window:
“System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element…”
What is happening here?
The Columns collection is just a property in the Datagrid; this collection is not in the logical (or visual) tree, therefore the DataContext is not being inherited, which leads to there being nothing to bind to.
I needed the functionality so I had to create a workaround.. With out much thought I decided to:
- Listen for DataContextChanged in the DataGrid
- When DataContext changes, forward the new value to the DataGridColumns in the datagrid.
- Bind properties on the DataGridColumn to this ‘forwarded’ DataContext ( as I originally intended)
To get it done, I did not inherit from DataGrid and create a new class.. Instead i used the richness of WPF’s property system to pull a 1,2 punch:
- Override DataGrid’s DataContext metadata and listen for changes in it…
- Add a FrameworkElement.DataContextProperty to DataGridColumn …
Code looks like this:
FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn)); FrameworkElement.DataContextProperty.OverrideMetadata ( typeof(DataGrid), new FrameworkPropertyMetadata (null, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnDataContextChanged))); |
The OnDataContextChanged callback simply forwards the DataContext from DataGrid to its columns:
|
That is it. Now we are ready to databind to DataGridColumns.
<dg:DataGridTextColumn Binding="{BindingA}"
Visibility="{Binding ElementName=ShowA,Path=IsChecked ,
Converter={StaticResource BoolToVisConverter}}" />
You can download source code for a small sample from here.
A few more thoughts on DataGridColumn not being in the tree ..
Binding to other UIElements via ElementName will not work because there is no tree.
Binding to a StaticResource works fine..
Binding to x:Static will work fine too.
Happy datagrid coding.. Again, there is source here.