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 ResourceInjectionDemo UserControl:
public partial class ResourceInjectionDemo : UserControl
{
public ResourceInjectionDemo()
{
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:
<UserControl
x:Class="ArtificialInheritanceContextDemo.ResourceInjectionDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ComboBox
Grid.Row="0"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"
/>
<ListBox x:Name="_listBox" Grid.Row="1" Margin="4">
<ListBoxItem Content="Fully Opaque" IsSelected="True">
<ListBoxItem.Tag>
-->
<Image
DataContext="{DynamicResource DATA_HistoricDocuments}"
Opacity="1"
Source="{Binding PhotoUri}"
Width="300" Height="350"
/>
</ListBoxItem.Tag>
</ListBoxItem>
<ListBoxItem Content="Semi-Transparent">
<ListBoxItem.Tag>
<Image
DataContext="{DynamicResource DATA_HistoricDocuments}"
Opacity="0.5"
Source="{Binding PhotoUri}"
Width="300" Height="350"
/>
</ListBoxItem.Tag>
</ListBoxItem>
</ListBox>
<Viewbox Grid.Row="2" Stretch="Fill">
<TextBlock
FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Path=Name}"
>
<TextBlock.Foreground>
<VisualBrush
Visual="{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.
Here is the DataContextSpy class:
public class DataContextSpy
: Freezable {
public DataContextSpy()
{
BindingOperations.SetBinding(this, DataContextProperty, new Binding());
this.IsSynchronizedWithCurrentItem = true;
}
public bool IsSynchronizedWithCurrentItem { get; set; }
public object DataContext
{
get { return (object)GetValue(DataContextProperty); }
set { SetValue(DataContextProperty, value); }
}
public static readonly DependencyProperty DataContextProperty =
FrameworkElement.DataContextProperty.AddOwner(
typeof(DataContextSpy),
new PropertyMetadata(null, null, OnCoerceDataContext));
static object OnCoerceDataContext(DependencyObject depObj, object value)
{
DataContextSpy spy = depObj as DataContextSpy;
if (spy == null)
return value;
if (spy.IsSynchronizedWithCurrentItem)
{
ICollectionView view = CollectionViewSource.GetDefaultView(value);
if (view != null)
return view.CurrentItem;
}
return value;
}
protected override Freezable CreateInstanceCore()
{
throw new NotImplementedException();
}
}
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 DataContextSpyDemo UserControl has no logic in the code-behind, so let’s jump straight to the XAML to see how it works:
<UserControl
x:Class="ArtificialInheritanceContextDemo.DataContextSpyDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ArtificialInheritanceContextDemo"
>
<UserControl.DataContext>
<ObjectDataProvider
MethodName="GetDocuments"
ObjectType="{x:Type local:HistoricDocument}"
/>
</UserControl.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ComboBox
Grid.Row="0"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"
/>
<ListBox x:Name="_listBox" Grid.Row="1" Margin="4">
<ListBox.Resources>
-->
<local:DataContextSpy x:Key="spy" />
</ListBox.Resources>
<ListBoxItem Content="Fully Opaque" IsSelected="True">
<ListBoxItem.Tag>
<Image
DataContext="{Binding Source={StaticResource spy}, Path=DataContext}"
Opacity="1"
Source="{Binding PhotoUri}"
Width="300" Height="350"
/>
</ListBoxItem.Tag>
</ListBoxItem>
<ListBoxItem Content="Semi-Transparent">
<ListBoxItem.Tag>
<Image
DataContext="{Binding Source={StaticResource spy}, Path=DataContext}"
Opacity="0.5"
Source="{Binding PhotoUri}"
Width="300" Height="350"
/>
</ListBoxItem.Tag>
</ListBoxItem>
</ListBox>
<Viewbox Grid.Row="2" Stretch="Fill">
<TextBlock
FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Path=Name}"
>
<TextBlock.Foreground>
<VisualBrush
Visual="{Binding ElementName=_listBox, Path=SelectedItem.Tag}"
/>
</TextBlock.Foreground>
</TextBlock>
</Viewbox>
</Grid>
</UserControl>
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.
Here is the code-behind for the VirtualBranchDemo UserControl:
public partial class VirtualBranchDemo : UserControl
{
public VirtualBranchDemo()
{
this.InitializeComponent();
base.DataContext = HistoricDocument.GetDocuments();
}
}
The DataContext of the control is set in code because there is a binding in XAML that pushes the property value over to the virtual branch. The XAML file is shown below:
<UserControl
x:Class="ArtificialInheritanceContextDemo.VirtualBranchDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ArtificialInheritanceContextDemo"
>
<UserControl.Resources>
<FrameworkElement x:Key="bridge" />
</UserControl.Resources>
<UserControl.DataContext>
<Binding
Mode="OneWayToSource"
Path="DataContext"
Source="{StaticResource bridge}"
/>
</UserControl.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ComboBox
Grid.Row="0"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"
/>
<ListBox x:Name="_listBox" Grid.Row="1" Margin="4">
<ListBoxItem Content="Fully Opaque" IsSelected="True">
<ListBoxItem.Tag>
<Image
DataContext="{Binding Source={StaticResource bridge}, Path=DataContext}"
Opacity="1"
Source="{Binding PhotoUri}"
Width="300" Height="350"
/>
</ListBoxItem.Tag>
</ListBoxItem>
<ListBoxItem Content="Semi-Transparent">
<ListBoxItem.Tag>
<Image
DataContext="{Binding Source={StaticResource bridge}, Path=DataContext}"
Opacity="0.5"
Source="{Binding PhotoUri}"
Width="300" Height="350"
/>
</ListBoxItem.Tag>
</ListBoxItem>
</ListBox>
<Viewbox Grid.Row="2" Stretch="Fill">
<TextBlock
FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Path=Name}"
>
<TextBlock.Foreground>
<VisualBrush
Visual="{Binding ElementName=_listBox, Path=SelectedItem.Tag}"
/>
</TextBlock.Foreground>
</TextBlock>
</Viewbox>
</Grid>
</UserControl>
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)
Revision History
- July 2, 2008 – Created the article.