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 element contains two DataTrigger , which, depending on the value of the Value property, set a different value to the Content property of the ContentControl element. In the first case, the Button element is set as the value, and the простой текст in the second, which is taken from the TestData property.

As you can see in the Button element there is 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. When configuring the Binding , the RelativeSource property is used, which allows you to specify 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, that is, the binding to the TestData property TestData not occur.

At the same time, a similar binding, in which a simple text is specified, works 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 a button otherwise:

 <Button Background="Aquamarine" Content="{Binding TestData}" /> 

then everything will work fine.

I would like to understand the features of this behavior, why is the binding in the button specified using RelativeSource not working, but the simple Binding opposite?

  • And if so: pastebin.com/VCuXw1BN ? - VladD
  • one
    @VladD, this solution works, but if I can say, I’m not looking for alternative ways to solve the problem, but try to get to the truth and understand the details) Ie Why is the button binding set using RelativeSource not working, what happens inside the magic? It would seem that the button in the visual tree is present so what is the problem then to take and find its parent Window and bind to the property from its DataContext . - sp7
  • Well, I think the problem is that you are trying to insert a control in the form of content not through a template. - VladD
  • one
    @VladD just somehow strangely turns out, the Content="{Binding TestData}" binding Content="{Binding TestData}" in the button works, I expected similar behavior when using RelativeSource . In fact, after all, these bindings set the same thing in just different ways or am I mistaken? - sp7
  • I have a suspicion that it should not work this way, and the fact that it works with a different binding is an accident. UI elements can be propagated only through a template, otherwise surprises are possible (but it is possible that an exception will not necessarily be ). - VladD

1 answer 1

It seems to me that the option of binding the button does not work out because, in fact, when the trigger is triggered, it has not yet been placed in the visual tree. Therefore, it cannot find an ancestor and borrow its datacontext. If you are working in Visual Studio, then opening the Output window will most likely see an error message of this kind.

In the case where you just bin the content of an 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, so it can also find the predecessor. Binding without RelativeSource works out because it refers directly to the context container in which it is placed.