views:

1752

answers:

2

Having {Binding ElementName=foo}, will it lookup visual or logical tree?

http://blogs.msdn.com/mikehillberg/archive/2008/05/23/Of-logical-and-visual-trees-in-WPF.aspx

When does the logical tree matter?

When looking up a name, such as in {Binding ElementName=Foo}, the search walks up the ancestry looking for a name scope, again just as it does for inheritable properties.

http://www.scottlogic.co.uk/blog/wpf/2009/02/elementname-binding-in-silverlight-via-attached-behaviours/

In order to enable this, WPF provides ElementName and RelativeSource bindings, giving you a powerful mechanism for locating other elements within your visual tree to bind to

EDIT:

It looks like the LogicalTree used for binding by ElementName.

Argument # 1.

According to MSDN article FrameworkElement Class:

FrameworkElement extends UIElement and adds the following capabilities:

  • Support for data binding and dynamic resource references: The property-level support for data binding and resources is implemented by the DependencyProperty class and embodied in the property system, but the ability to resolve a member value that is stored as an Expression (the programming construct that underlies both data binding and dynamic resources) is implemented by FrameworkElement. For more information, see Data Binding Overview and Resources Overview.

Argument # 2.

ElementName points to x:Name, so this name should be found some how. There is a NameScope concept.

For most scenarios, the FindName methods exposed on FrameworkElement and FrameworkContentElement are more appropriate methods to call to search for elements by name. The Name properties exposed by FrameworkElement and FrameworkContentElement are more appropriate properties to use to set the initial name as markup attributes. And the RegisterName methods exposed on FrameworkElement and FrameworkContentElement is necessary to establish a name into a specific namescope (there is no NameScope member that can do this directly; you must set the current namescope first to use RegisterName).

On the other hand, Visual class neither have FindName method, nor implement INameScope.

A: 

The short answer is that it looks up the VisualTree.

Take a look at this example -

<Window x:Class="DataBinding2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataBinding2" Loaded="Window_Loaded"
Title="Window1">

<DockPanel>

    <Slider DockPanel.Dock="Top"></Slider>
    <TextBlock DockPanel.Dock="Top" Text="ElementName Binding" FontWeight="Bold"/>
    <TextBlock DockPanel.Dock="Top" Text="{Binding ElementName=PART_Track}"/>

    <TextBlock DockPanel.Dock="Top" Text="VisualTreeHelper Lookup" FontWeight="Bold"/>
    <TextBlock DockPanel.Dock="Top" x:Name="vttxt"  />

    <TextBlock DockPanel.Dock="Top" Text="LogicalTreeHelper Lookup" FontWeight="Bold"/>
    <TextBlock DockPanel.Dock="Top" x:Name="lttxt"  />
</DockPanel>

using System.Collections;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media;

namespace DataBinding2
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

            DependencyObject track = FindVisualChild<Track>(this);
            DependencyObject track2 = FindLogicalChild<Track>(this);
            vttxt.Text = track != null ? track.ToString() : "NULL";
            lttxt.Text = track2!=null ? track2.ToString() : "NULL" ;

        }

        public childItem FindVisualChild<childItem>(DependencyObject obj)
           where childItem : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);

                if (child != null && child is childItem)
                    return (childItem)child;

                else
                {
                    childItem childOfChild = FindVisualChild<childItem>(child);

                    if (childOfChild != null)
                        return childOfChild;
                }
            }

            return null;
        }

        public childItem FindLogicalChild<childItem>(DependencyObject obj)
           where childItem : DependencyObject
        {
            IEnumerable children = LogicalTreeHelper.GetChildren(obj);
            int count = 0;
            foreach (var v in children)
            {
                count++;
                DependencyObject child = v as DependencyObject;

                if (child != null && child is childItem)
                    return (childItem)child;

                else
                {
                    childItem childOfChild = null;

                    if (child != null)
                    {
                        childOfChild = FindLogicalChild<childItem>(child);
                    }

                    if (childOfChild != null)
                        return childOfChild;
                }
            }
            return null;
        }


    }
}

In the example, if you step through it you'll get a better understanding of what the differences are between the two element trees. You should also see that looking through the VisualTree you can find the Track even though it internal to the Slider but you can't with the LogicalTree

You'll VERY rarely need to traverse the LogcialTree; it's mostly there since the framework uses it to resolve DependencyProperties and Resources,...things that aren't necessarily visual.

For more info on the differences take a look at http://www.codeproject.com/KB/WPF/WpfElementTrees.aspx.

Hope this helps.

Stimul8d
I get empty "ElementName Binding". Are you sure that binding to PART_Track works?
alex2k8
+1  A: 

I think it's logical tree. When using ControlTemplates, you're replacing one visual tree with another, but I don't think you can reference the names defined inside of the ControlTemplate.

For example:

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
    <Grid>
     <Grid.Resources>
      <ControlTemplate x:Key="Foo" TargetType="Button">
       <Border x:Name="border" Background="Red">
          <Label Content="{TemplateBinding Content}"></Label>
       </Border>
      </ControlTemplate>
       </Grid.Resources>
       <Grid.ColumnDefinitions>
      <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
       </Grid.ColumnDefinitions>
       <Button x:Name="buttonFoo" Background="Green" HorizontalAlignment="Center" VerticalAlignment="Center" Template="{DynamicResource Foo}">Foo</Button>
       <Label x:Name="labelBar" Grid.Column="1"  HorizontalAlignment="Center" VerticalAlignment="Center" Background="{Binding ElementName=border, Path=Background}">Bar</Label>
    </Grid>
</Page>

Doesn't find the element named "border" in the ControlTemplate, but changing ElementName in labelBar's binding to "buttonFoo" makes the Background Green, as expected.

micahtan