Introduction

This article discusses and demonstrates three ways to simulate having an inheritance context for DependencyObjects external to an element tree. In this article, we examine how to use artificial inheritance contexts to enable data binding to work in situations that would not work otherwise. This article’s demo program shows how to use all three techniques. Toward the end of this article, there is a section comparing the pros and cons of each technique.

Background

You can register a dependency property with the WPF property system so that its value inherits down the element tree, technically the logical tree. The canonical example is the FontSize property. If you set FontSize on a Window, all elements in that Window will display text at that size. If you specify a different FontSize on, say, a GroupBox in the Window, all of the elements in the GroupBox will inherit and use that new FontSize instead of the Window’s FontSize. This is similar to ambient properties in Windows Forms.

Another inheritable dependency property on both the FrameworkElement and FrameworkContentElement classes is DataContext, which acts like an ambient, implicit data source for all data bindings in an element tree. When a property of an element is bound and the Binding’s Source, RelativeSource, and ElementName properties are not set, the Binding automatically binds to the element's DataContext. This is a powerful feature of the WPF framework because, in practice, most bindings are between an element property and a property on the data context object. This is one reason why WPF is a great data-driven user interface platform.

This system breaks down when you try to bind a property on an object that is not in the element tree. One example of this is if you try to bind a property on the object referenced by an element’s Tag property. You can set an element’s Tag to a visual element, but that element is not in an element tree. WPF will not add that element to an element tree because it is not actually part of the user interface; it is just some visual element sitting in memory. Since the element is not in an element tree, it does not have an inheritance context, which means that it cannot bind to an inherited DataContext. The key here is that when an element is not in the element tree, it cannot inherit dependency property values. Value inheritance relies on what is known as an “inheritance context,” which is the internal infrastructure used to propagate values down an element tree. In addition, not having an inheritance context prevents bindings from being able to use the ElementName property to specify their source.

This article shows three ways to work around the problem of not having an inheritance context when data binding. Each technique manages to “export” an element tree’s DataContext to objects external to the tree.

The Demo

At the top of this article, you can download the demo project that accompanies this article. The app shows how to do the same task three ways. The task itself is rather trivial, and you could definitely implement it without the need for artificial inheritance contexts. However, as with many of my articles, I struggled to come up with a programming task that is simple enough to not “get in the way” yet complicated enough to allow me to demonstrate the technique under review.

The demo app allows the user to choose a historic document, such as the US Constitution, and view its name displayed in large text. The document name paints with a brush that displays a photograph of the document. The UI also contains a ListBox with two options. If you select “Fully Opaque”, the photo is displayed at full opacity; otherwise, if you select “Semi-Transparent”, it displays at half opacity.

As seen in the screenshot below, when viewing the US Constitution, the text paints with a photo of the US Constitution at full opacity:

As I mentioned before, this simple (and bizarre!) application could easily be created without using an artificial inheritance context. Most real-world situations that require an artificial inheritance context are more complicated and obscure than this stupid little programming task.

Resource Injection

The quickest and least complicated way to gain access to a DataContext, or any other object for that matter, from elements not in an element tree is to inject it into the resource system. The trick here is to rely on the fact that a DynamicResource reference will check the Application’s Resources collection, upon creation, for a resource with a matching resource key. This even occurs if the DynamicResource is on a property of an element that is not in an element tree. Note, however, that unlike normal DynamicResource references, a subsequent update made to the resource in App.Resources will not be noticed and honored. In essence, they act like StaticResource references in this situation.

The other trick to know is that the resource must be added to App.Resources before the DynamicResources are created. In practice, this usually means that you must load your data context object and put it into App.Resources before the Window/Page/UserControl constructor calls InitializeComponent. This ensures that the one-time check for a matching resource in App.Resources made by each DynamicResource reference will be successful.

Here is the code-behind for the ResourceInjectionDemoUserControl:

publicpartialclass ResourceInjectionDemo : UserControl
{
public ResourceInjectionDemo()
{
// After setting our DataContext, inject it into the App's
// Resources so that it is visible to all DynamicResource references.
// NOTE: This must be done *before* the call to InitializeComponent
// since DynamicResource references for objects not in the logical tree
// only check the App's Resources once, upon creation.
// This only works once. After the call to InitializeComponent, updating
// the resource value to a new datacontext object will have no effect.
base.DataContext = HistoricDocument.GetDocuments();
App.Current.Resources["DATA_HistoricDocuments"] = base.DataContext;this.InitializeComponent();
}
}

The resource key “DATA_HistoricDocuments” is an arbitrary identifier that I made up. You will see it in use in the control’s XAML file:

<UserControlx:Class="ArtificialInheritanceContextDemo.ResourceInjectionDemo"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Grid><Grid.RowDefinitions><RowDefinitionHeight="Auto"/><RowDefinitionHeight="Auto"/><RowDefinitionHeight="*"/></Grid.RowDefinitions><ComboBoxGrid.Row="0"IsSynchronizedWithCurrentItem="True"ItemsSource="{Binding}"Margin="4"/><ListBoxx:Name="_listBox"Grid.Row="1"Margin="4"><ListBoxItemContent="Fully Opaque"IsSelected="True"><ListBoxItem.Tag><!--
Get a reference to the DataContext by grabbing it from
the Application's Resources via a DynamicResource reference.
--><ImageDataContext="{DynamicResource DATA_HistoricDocuments}"Opacity="1"Source="{Binding PhotoUri}"Width="300"Height="350"/></ListBoxItem.Tag></ListBoxItem><ListBoxItemContent="Semi-Transparent"><ListBoxItem.Tag><ImageDataContext="{DynamicResource DATA_HistoricDocuments}"Opacity="0.5"Source="{Binding PhotoUri}"Width="300"Height="350"/></ListBoxItem.Tag></ListBoxItem></ListBox><ViewboxGrid.Row="2"Stretch="Fill"><TextBlockFontWeight="Bold"HorizontalAlignment="Center"VerticalAlignment="Center"Text="{Binding Path=Name}"><TextBlock.Foreground><VisualBrushVisual="{Binding ElementName=_listBox, Path=SelectedItem.Tag}"/></TextBlock.Foreground></TextBlock></Viewbox></Grid></UserControl>

DataContextSpy

A spy is a person who secretly examines the actions and information of other individuals or organizations and reports it to an external party. My DataContextSpy class does exactly that, only it observes the DataContext of an element tree, and external elements can bind against it to gain access to the DataContext. You simply add a DataContextSpy to the Resources collection of any element, except the element on which the DataContext was set, and its DataContext property will automagically expose the DataContext of that element.

This class uses the Hillberg Freezable Trick to gain access to the DataContext of the host element. That trick relies on the fact that WPF’s Freezable class has built-in support for getting an inheritance context, even though it is not in the element tree. For more information about how that works, I recommend you check out Dr. WPF’s thorough explanation here.

The DataContextSpyDemoUserControl has no logic in the code-behind, so let’s jump straight to the XAML to see how it works:

Virtual Branch of Logical Tree

The last technique we cover is something that I wrote an article about back in May 2007. I included a demonstration that uses a virtual branch in this article just for the sake of completeness. Creating a virtual branch of the logical tree is similar to using a DataContextSpy, only the element tree pushes the DataContext, instead of the DataContext being pulled from the element tree. The basic idea is that we export the DataContext property (or any property) via static resource references and a OneWayToSource binding.

Virtual branches are very flexible, and you can easily use them to export more than just the DataContext property of an element tree. The big downside, though, is that you must set up a OneWayToSource binding for the exported properties on the element which has that property setting applied to it. Whereas a DataContextSpy can be added to the Resources collection of any element except the one on which the DataContext was set, a virtual branch can only be established by the element on which the DataContext was set.

Pros and Cons of Each Technique

Each of these techniques has its own relative merits. I have listed all of the pros and cons that I could think of here to help make it easier to decide which approach to use. I am sure there must be other considerations that I have not listed, so please drop a comment on this article if you discover some.

Resource Injection

Pros

Easy to implement

Easy to understand

Cons

Pollutes App.Resources with global variables

Cannot set the DataContext to a new value

Requires the DataContext object to exist before InitializeComponent is called

DataContextSpy

Pros

Easy to implement

New DataContext will be honored

DataContext can be bound via ElementName, if necessary

Introduces very little to no impact on the element tree

Cons

Potentially confusing

Cannot be added to Resources of the element where the DataContext is set

Spying on other properties requires new properties on the DataContextSpy class

Virtual Branch

Pros

New DataContext will be honored

Easily export properties other than DataContext to a virtual branch via data binding

Cons

Potentially confusing

Requires the DataContext bridge to be bound by the element where the DataContext is set

Requires the element tree to export the DataContext (has impact on the element tree)

How would you feel about putting an invisible framework element in the visual tree, and binding to it by using the x:Reference markup extension? This is similar to binding by ElementName but apparently does not require an inheritance context!

This works for me to bind Visibility of DataGridTextBoxColumn (which is not in visual tree).

<FrameworkElement Name="dummyElement" />

Actually if you have anything else in your visual tree, you don't even need the dummy element ... you could use a TextBlock or whatever else you have in that same XAML file.

I have found this article very interesting and I wonder if I can use it to solve my issue:
I have a dynamecaly created columns of the GridView(collection) - both column header and items are defined using ControlTemplate and DataTemplate. I have to "connect" column header selection(check box)"IsChecked" to the "background" of the all cells of the selected column. In other works I need to highlight the spesific column.

As you point out, the bridge technique only works for the element on which the DataContext is set and the Spy only works on elements on which the DataContext is not directly set. Perhaps it would be possible to combine both techniques by adding a third "BridgeSpyAdapter" resource which wraps the bridge and spy and chooses between the DataContexts (only one will be non null?) It would then expose these as a new DependancyProperty to bind to.

I created an attached property (BindingHub) which contains a virtual branch of logical tree as well, and OnBindingHubChanged() I bind DataContext and NameScope to the parent's DataContext and NameScope. Voila, you can use {Binding xxx} and {Binding ElementName}...

Let me first say many thanks for the DataContextSpy class, I've used it many times in my WPF projects.

A question I have is if it's possible to get it working in Blend's design mode (I'm assigning a DataContext to a ViewModel class via a XAML StaticResource)?

For those wanting something similar to DataContextSpy for Silveright, you can use DataContextProxy (I renamed my version to DataContextSpy and the DataSource dependency property to DataContext so I can have API parity between my WPF/Silverlight projects).

It is working fine and displays the list. Now I want to be able to hide columns on user clicks a RibbonCheckBox. I created the property "ShowStockNumber" and it works pretty fine. I even wired the property to another CheckBox outside the Ribbon to make sure it is working. And it mimicing the tick pretty good. Which might mean that my property is working well with all the PropertyChanged events.

I have read in one off your blogs "You simply add a DataContextSpy to the Resources collection of any element, except the element on which the DataContext was set, and its DataContext property will automagically expose the DataContext of that element.."

I have tried to move the DataContextSpy to <UserControl.Resources>, I have tried to make the Path with and without the "DataContect." but cannot get this code to hide the column.

Thanx for your time!

Edit:
I figured my "missing" link. I used the same ShowStockNumber to link it to other properties such IsReadOnly and it worked. That is when the penny start to drop, thanx to the Naming convention... "IsXxx.." The Visibility property has three states! not bool. I just added the Converter={StaticResource BoolToVisibilityConverter}to the Binding and viola! it worked!

So the million dollar question; how can I use the collections of freezables? I'm trying to implement something like Style.Triggers, but alas, I can't. Most of the IAddChild implementations that do this sort of thing use InheritanceContextHelper to propogate the inhertance context from the parent to the child, but alas, this method is internal :(