What's an inheritance context?
I've been slacking on my blogging lately, so what better way to get back into the swing of things than to post an article I've been meaning to write for five months? But before I tell you about inheritance contexts, I have to explain the problem it solves. Once upon a time, property inheritance looked only at the logical tree and the visual tree -- so if an element didn't have a logical or visual parent, its properties didn't inherit values from the parent it didn't have. Which makes sense if you think about the world in terms of code. But if you look at the world through xaml glasses, there's a lot of places where one element looks like it has a parent when it really doesn't. Consider the following:
<Button>
<Button.Background>
<SolidColorBrush>green</SolidColorBrush>
</Button.Background>
</Button>
Quick, what's the parent of SolidColorBrush? If you said Button, you would be wrong -- SolidColorBrush is not part of the visual tree (it's not a Visual). Nor is SolidColorBrush part of the logical tree, because if you call Button.Content the answer is not the SolidColorBrush. So SolidColorBrush in this example has no parent, so it didn't inherit property values from anyone.
At first this may seem academic -- who cares if SolidColorBrush inherits? Actually, there's a couple reasons it matters, the DataContext property and the Loaded event. DataContext is an inherited property that use the default data source for your {Binding} statements. When you write:
<SolidColorBrush Color="{Binding}"/>
Since you didn't specify a data source (and who does), it uses the DataContext property. And if that inherits the way you expect, everything is happy. But it's easy to write:
<Button DataContext="whatever">
<Button.Background>
<SolidColorBrush Color="{Binding}"/>
</Button.Background>
</Button>
And be confused that your SolidColorBrush didn't inherit the DataContext. Similarly, the Loaded event was originally tied to the logical tree, so if you put your MediaElement inside a VisualBrush, there would be a gap in the visual tree and your media would never get a Loaded event and never start play the video.
And that's why we invented inheritance context. You can think of it as logical tree 2.0 -- inheritance context is an extra pointer, which the property engine uses when there's no logical parent or visual parent to get values from. Inheritance context don't solve every problem in this space, but they solve a lot of them, and in the future we'll add more inheritance context pointers and solve more problems.
There's a number of places we establish inheritance context pointers, I won't try to list all of them but here are some of the more interesting ones:
Freezable inside a FrameworkElement -- our SolidColorBrush/Button sample above
FrameworkElement inside a VisualBrush
Triggers and setters
Resource dictionaries present another interesting case. Suppose you use DynamicResource inside a resource dictionary:
<Window.Resources>
<SolidColorBrush Color="{DynamicResource ...}" />
</Window.Resources>
Does that dynamic resource get evaluated where the SolidColorBrush was defined? Or where the brush gets used? If the latter, what happens if you use the SolidColorBrush in two different places where the DynamicResource will give two different answers? It may sound contrived:
<Window.Resources>
<Color x:Key="color">red</Color>
<SolidColorBrush x:Key="brush" Color="{DynamicResource color}" />
</Window.Resources>
<Button>
<Button.Background>
<StaticResource ResourceKey="brush"/>
</Button.Background>
</Button>
<Button>
<Button.Resources>
<Color x:Key="color">blue</Color>
</Button.Resources>
<Button.Background>
<StaticResource ResourceKey="brush"/>
</Button.Background>
</Button>
But it actually happens in real code. We chose the first solution, the inheritance context for SolidColorBrush points to the resource dictionary, and not its point of use.
Inheritance context has been wonderfully useful, but we haven't put inheritance context links everywhere that's theoretically possible, mostly because of time in the day (adding inheritance context links are very difficult to implement performantly and without causing undesired behavior changes). Probably the simplest example of where we don't have inheritance context links is across random property elements:
<Button>
<Button.ContextMenu>
<ContextMenu/>
</Button.ContextMenu>
</Button>
ContextMenu is neither a visual nor logical child of Button, nor is it one of the inheritance context cases listed above (ContextMenu is not a Freezable). But, with inheritance context concept at our disposal, we hope to solve that in future versions of WPF.
Comments
Anonymous
August 17, 2006
The ContextMenu example you mentioned was actually the one that gave me the biggest headache. I was trying to Databind my Context Menu Items to a property of the DataContext in my parent element, and it took me a long time to work out why it didn't work.
In the end I had to resort to code to set up the Context Menu, which was a shame. What would be the best way of solving this problem? Am I right in thinking that even an ElementName binding to an Element higher up the tree would fail?Anonymous
August 18, 2006
Yes, FindName on the context menu would not find anything because the context menu has no parent pointers.
For binding, the best solution is to explicitly set the DataContext on the context menu, and/or set the binding's Source (Either in code or xaml). Most of the time, that works just fine, the place where it breaks down is when you're doing item templates and/or hierarchical data binding, in that case is often a lot harder for you to calculate yourself what the data context should be.Anonymous
July 17, 2008
PingBack from http://agsmith.wordpress.com/2008/07/17/elementname-binding-in-tooltips-borrowing-a-namescope/Anonymous
January 21, 2009
PingBack from http://www.keyongtech.com/433279-wpf-databinding-problemAnonymous
May 12, 2009
Playing with SL3, I did a small research to find differences between Relative Binding and TemplateBindingAnonymous
May 12, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding/Anonymous
May 12, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-2/Anonymous
May 12, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-3/Anonymous
May 12, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-5/Anonymous
May 12, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-15/Anonymous
May 12, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-16/Anonymous
May 12, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-14/Anonymous
May 14, 2009
Introduction I’ve always had mixed feelings toward animations in cases of generic controls, panels orAnonymous
May 20, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-4/Anonymous
May 20, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-6/Anonymous
May 20, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-7/Anonymous
May 20, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-8/Anonymous
May 20, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-9/Anonymous
May 20, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-11/Anonymous
May 20, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-12/Anonymous
May 20, 2009
PingBack from http://www.codedstyle.com/silverlight-3-template-binding-vs-relative-binding-13/Anonymous
June 04, 2009
PingBack from http://www.top-silverlight.com/2009/05/14/how-to-create-generic-animated-panels-in-silverlight-2-and-3-animations-part-i.html