WPF TemplateBinding vs. RelativeSource TemplatedParent
Trying to get the bindings right for a certain ControlTemplate I wanted to have for a TabControl lead me to an interesting observation on TemplateBinding that was not so obvious. In the TabControl's ControlTemplate, I wanted to have an inner ItemsControl binding to the templated TabControl's Items (and thus replace the default TabPanels).
It ended up working with a RelativeSource binding like this:
<ControlTemplate x:Key="CustomTabControlTemplate" TargetType="{x:Type TabControl}">
...
<ItemsControl Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" >
<ItemsControl.ItemsSource>
<Binding Mode="OneWay" Path="Items">
<Binding.RelativeSource>
<RelativeSource
Mode="TemplatedParent"
/>
</Binding.RelativeSource>
</Binding>
</ItemsControl.ItemsSource>
</ItemsControl>
I was intrigued that using the more usual TemplateBinding did not work (you get a compile time error):
<ItemsControl ItemsSource="{TemplateBinding Items}" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" />
From the TemplateBinding docs, one can get the (wrong) impression that it should actually work. It says:
A TemplateBinding is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with {Binding RelativeSource={RelativeSource TemplatedParent} Mode=OneWay}.
The word "analogous" is misleading. At a search, it was clear that there are significant differences under the hood between Binding and TemplateBinding. Some of them are described here, however, none of them seemed to apply, which is why I tried to look again more carefully at the docs. And there's the explanation right on the TemplateBinding docs page: unlike a Binding, a TemplateBinding can only bind a DependencyProperty to another DependencyPropery (IMHO, the wording of "targetProperty" in the docs below is confusing/wrong from a WPF binding terminology perspective, because the property on the type being templated is actually the source, the target being propertyName !):
|
|
|
|
But Items in an ItemsControl is not a DependencyProperty (ItemsSource is !) which is why only a RelativeSource Binding works in this case.