2
votes

To understand how the binding works, I implemented MyContainer derived from FrameworkElement. This container allowes to set Children and adds them into the logical tree. But the binding by ElementName does not work. What can I do with MyContainer to make it work, leaving the parent as FrameworkElement?

C#:

public class MyContainer : FrameworkElement
{
    public MyContainer()
    {
        Children = new List<FrameworkElement>();
    }

    public List<FrameworkElement> Children { get; set; }
    protected override IEnumerator LogicalChildren
    {
        get { return Children.GetEnumerator(); }
    }
}

XAML:

<Window x:Class="WpfLogicalTree.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfLogicalTree"
    Title="Window1" Height="300" Width="300">
    <StackPanel>

        <local:MyContainer>
            <local:MyContainer.Children>
                <TextBlock Text="Foo" x:Name="_source" />
                <TextBlock Text="{Binding Path=Text, ElementName=_source}" x:Name="_target"/>
            </local:MyContainer.Children>   
        </local:MyContainer>

        <Button Click="Button_Click">Test</Button>

    </StackPanel>
</Window>

Window1.cs

private void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show(_target.Text);
}
1

1 Answers

3
votes

Instead of using LogicalChildren I had to call AddLogicalChild. So this works:

public class MyContainer : FrameworkElement
{
    public MyContainer()
    {
        Children = new List<FrameworkElement>();
        this.Loaded += new RoutedEventHandler(OnLoaded);
    }

    void  OnLoaded(object sender, RoutedEventArgs e)
    {
        foreach (FrameworkElement fe in Children)
            this.AddLogicalChild(fe);
    }        

    public List<FrameworkElement> Children { get; set; }
}

AddLogicalChild sets the logical parent of the element, this is required to find NameScope where the "_source" name was registered. In our case the Name Scope is the Window1.

Note. AddLogicalChild will not result in LogicalChildren returning our children automatically, it only sets the Parent. So LogicalTreeHelper.GetChildren will be the empty collection. But we don't need it here.