c# – Features of the RelativeSource binding

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.

Scroll to Top