Question:
There is a window that contains the following XAML
markup:
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding Value}" Value="1">
<Setter Property="Content">
<Setter.Value>
<Button Background="Aquamarine"
Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TestData}" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Value}" Value="2">
<Setter Property="Content"
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TestData}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
<Button Grid.Row="1"
Command="{Binding DoCommand}"
Content="Тыц" />
</Grid>
In this window, the ContentControl
contains two DataTrigger
that, depending on the value of the Value
property, set a different value to the Content
property of the ContentControl
. In the first case, the Button
element is set as the value, in the second – простой текст
, which is taken from the TestData
property.
As you can see, the Button
element has a binding to the TestData
property located in the ViewModel
, and it is set as follows:
<Button Background="Aquamarine"
Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TestData}" />
those. the Binding
configuration uses the RelativeSource
property to set the binding source relative to the current object. The problem is that for some reason, the current Binding
configuration for the button does not work, i.e. the binding to the TestData
property TestData
not occur.
At the same time, a similar binding, in which a simple text is set, works out successfully.
<Setter Property="Content" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TestData}" />
In addition, if you rewrite the Binding
for the button differently:
<Button Background="Aquamarine" Content="{Binding TestData}" />
then everything will work fine.
I would like to understand the features of this behavior, why the binding in the button specified using the RelativeSource
does not work, and the simple Binding
other way around?
Answer:
It seems to me that the option with button binding does not work because, in fact, at the time of triggering, it has not yet been placed in the visual tree. Therefore, it cannot find the ancestor and borrow its datacontext. If you are working in Visual Studio, then when you open the Output window, you will most likely see an error message of this kind.
In the case where you simply bind the content of the already existing content control to the same property, everything works, and this is logical, because the content of the control itself has already been placed in the visual tree, and accordingly it can find the given ancestor. Binding without a RelativeSource works because it refers directly to the date context of the container it is placed in.