Search code examples
c#wpfmultibindingfindancestor

WPF Multibinding RelativeSource Findancestor evaluation performance


In the case of the following MultiBinding expression how many times will the binding engine search for the DataGrid ancestor IF the PropB is changed multiple times?

<MultiBinding Converter="{StaticResource TestConverter}"> 
    <Binding Path="PropA"/> 
    <Binding Path="PropB" /> 
    <Binding Path="DataContext.Sub.PropertyC" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=DataGrid}" /> 
</MultiBinding>

Will it search only once if the PropertyC (and the path to it) is never changed? Or will it search the ancestor each time one of the Properties in the multibinding is changed? Assuming there are change notifications on each property.


Solution

  • The only way I see possible to test this is by actually removing controls in order to see if it finds the proper control.

    Testing it this way, it looks as if it is evaluated only once whether using a MultiBinding or not.

    <Window x:Class="RelativeTest.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel x:Name="Stack">
            <TextBlock x:Name="TB1" Text="Foo" />
            <TextBlock x:Name="TB2" Text="Bar" />
    
            <Border BorderThickness="1" BorderBrush="Black" />
    
            <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[0].Text}" 
                       Foreground="Red" />
    
            <TextBlock Foreground="Blue">
                <TextBlock.Text>
                    <MultiBinding StringFormat="{}{2}">
                        <Binding ElementName="TB1" Path="Text" />
                        <Binding ElementName="TB2" Path="Text" />
                        <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=StackPanel}" Path="Children[0].Text" />
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
            <Button Click="ButtonBase_OnClick" Content="Remove 1st Child" />
        </StackPanel>
    </Window>
    
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    
        void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            Stack.Children.Remove(Stack.Children[0]);
            TB1.Text = "You'll see me if I am looked up once.";
            TB2.Text = "You'll see me twice if I am re-evaulated each time";
        }
    }
    

    When running it initially you will see:

    enter image description here

    When clicking the button, it will remove the first child and change the TextBlocks to display newer text to indicate which one it now binds to.

    enter image description here