wpfrelativesourcefindancestor

Using FindAncestor from within an Itemscontrol datatemplate to find a textblock outside of the datatemplate


I have a ItemsControl that's bound to an object, within the datatemplate of the ItemsControl i have two textblocks, I want to bind the first textblock's text property to another textblock that sits outside this ItemsControl.

I have tried finding the object in the parent datacontext and also simply trying to find the TextBlock with the Path=Text

one example is below :

 <TextBlock Name="Name" Text="{Binding Name}"                                                            
     Grid.Column="0"   
     FontSize="{DynamicResource SmallSize}"
     TextWrapping="Wrap"
     TextAlignment="Right"
     Padding="4,0,0,0"
     Grid.ColumnSpan="2" Background="Aqua"/>

     <ItemsControl ItemsSource="{Binding TheValue}"                                                  
         Padding="4,0,0,0" 
         Grid.Column="2"  
         HorizontalAlignment="Right">

         <ItemsControl.ItemTemplate>
             <DataTemplate>
                 <WrapPanel>
                     <TextBlock Text = "{
                           Binding RelativeSource = 
                               {RelativeSource FindAncestor, 
                                AncestorType={x:Type Window}}, Path=Name}"                                                                                                            
                           Grid.Column="0"
                           FontSize="{DynamicResource SmallSize}"
                           TextWrapping="Wrap" ........................

Solution

  • {Binding RelativeSource = {RelativeSource FindAncestor,
                               AncestorType={x:Type Window}}, Path=Name}
    

    Here you say to WPF find first parent of this control with Type Window, e.g. it's "ParentWindow". After this binding occurs to "ParentWindow" Name property.

    If you want enable binding to control, which defined in same XAML, you can set the source explicitly by using Binding.ElementName property. This is example for you code:

    <TextBlock Text = "{Binding ElementName=Name, Path=Text}"/>
    

    By the way, using control name as "Name" not is good. If you use this control form code behind it's looking as Name.Text = "some text", which can cause a trouble to understand what is going on.

    UPDATE: Example of binding to control DataContext Property in different datatemplate

    class MainViewModel
    {
        public Class1 C1 { get; set; }
        public Class2 C2 { get; set; }
    
        public MainViewModel()
        {
            C1 = new Class1 { S1 = "This is C1 data context" };
            C2 = new Class2 { S2 = "This is C2 data context" };
        }
    }
    

    In XAML:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"        
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <DataTemplate DataType="{x:Type local:MainViewModel}">
                <StackPanel>
                    <ContentControl Name="cc1" Content="{Binding C1}"/>
                    <ContentControl Name="cc2" Content="{Binding C2}"/>
                </StackPanel>
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:Class1}">
                <TextBlock Text="{Binding S1}"/>
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:Class2}">
                <TextBlock Text="{Binding ElementName=cc1, Path=DataContext.C1.S1}"/>
            </DataTemplate>
        </Window.Resources>
    
        <Grid>
            <ContentControl Content="{Binding}"/>
        </Grid>
    </Window>
    

    But, I don't think something like this is a good approach. Especially, because this can be many items with this DataTemplate. Maybe you need delegate this to your ViewModel.