共用方式為


VisualTreeHelper

A very useful class in Silverlight that is not as well known as it deserves to be is the VisualTreeHelper class. It contains four methods. One is FindElementsInHostCoordinates, which is used to programatically "hit test" the visual tree and determine what elements are under a given point in the plugin. This can be very useful at times (for example in drag-and-drop type scenarios).

The other three methods in the class, GetParent, GetChildrenCount and GetChild (all self explanatory) are used to navigate the visual tree. Silverlight (and also WPF) has two different concepts of the tree of UI elements; the "logical" tree and the "visual" tree. Roughly, the structure of the logical tree is what you see in XAML, whereas the visual tree also includes the expanded templates of any Controls/DataTemplates, etc. So for example if you have a Button containing an Image, then the Image is the logical child of the Button, but the visual children of the Button contains all of the chrome of the Button (the ControlTemplate as defined in generic.xaml), the ContentPresenter element which displays the Image and the Image element itself.

When it comes to manipulating the visual tree, I find that this is a useful extension method to have around:

public static IEnumerable<DependencyObject> GetVisuals(this DependencyObject root)

{

    int count = VisualTreeHelper.GetChildrenCount(root);

    for (int i = 0; i < count; i++)

    {

        var child = VisualTreeHelper.GetChild(root, i);

        yield return child;

        foreach (var descendants in child.GetVisuals())

        {

            yield return descendants;

        }

    }

}

(Note the use of the yield return syntax; another feature that is not as widely known about as it deserves.)

You can use this method to search through all of the children of a given element; much easier than trying to navigate through the tree using the element's object model (e.g. examining the "Children" property of Panels, the "Content" property of ContentControls, the "Child" property of Borders, etc.). Since it deals with IEnumerables, it also plays very nicely with LINQ expressions; consider this snippet of code to disable all the controls on a page:

 

foreach (var control in LayoutRoot.GetVisuals().OfType<Control>())

{

    control.IsEnabled = false;

}

 

VisualTreeHelper is a pretty simple class, but it can be extremely useful at times.

Comments

  • Anonymous
    March 29, 2009
    PingBack from http://www.anith.com/?p=24197

  • Anonymous
    April 12, 2009
    Thanks for the post, I found it very useful when trying to discover what listboxitem a button is in when when the button is clicked. Although I'm not sure why I had to use the Visual, rather than Logical, Tree to walk the tree.

  • Anonymous
    August 03, 2009
    Thanks for the code/idea.  This is useful in finding usercontrols and controls for which events must be removed in order to let garbage collection do its work. As you know, if one event is left on a control, it will never be removed from memory via garbage collection...Or, more importantly, as related to this code, if a parent of a parent, of a parent, of a parent... is removed from the visual tree, but some descendent still has an event attached, the whole tree, though now removed from the visual tree, will never be removed from memory until the browser is closed.

  • Anonymous
    December 02, 2009
    Thank you, very handy extension method. Just saved me many lines of code and that´s always very appreciated. Thanks.

  • Anonymous
    December 06, 2009
    Many Thanks for the extension method.

  • Anonymous
    April 25, 2010
    sorry,if i using "GetChildrenCount" on TabControl or some else customer controls,it always return 0, so i can't recursive it ..