Linq to Visual Tree

Friday, November 20, 2009 / Posted by Luke Puplett /

Over on Peter McGrattan’s blog is a simple extension method for a DependencyObject which returns the visual tree descending from a particular visual element in a WPF application. The genius in Peter’s simple extension is that it automatically leverages the power of LINQ because the tree is IEnumerable:

myPanel.GetVisualOfType<TextBox>().Where(t => t.Foreground... etc

But I had a problem: the tree would not descend fully.

To cut a long story short, the issue was caused because VisualTreeHelper.GetChildrenCount doesn’t count the content of a ContentControl as a child.

The following is my version of Peter’s good work – this is just one method cut from the original class, so I implore you to head over to his blog and see the whole thing. I have made the following changes:

  • Added support for ContentControl objects.
  • Modified the type checking to use IsAssignableFrom so types can be collated using their base classes.
public static IEnumerable<T> GetVisualOfType<T>(this DependencyObject element)         

    return GetVisualTree(element).Where(
        t => typeof(T).IsAssignableFrom(t.GetType())).Cast<T>();
}
public static IEnumerable<DependencyObject> GetVisualTree(this DependencyObject element)
{
    int childrenCount = VisualTreeHelper.GetChildrenCount(element);

    if ((childrenCount == 0) && (element is ContentControl))
    { 
        ContentControl cc = element as ContentControl;
        if (cc.Content != null)
        {
            DependencyObject content = cc.Content as DependencyObject;

            if (content != null)
            {
                yield return content;
                foreach (DependencyObject obj in GetVisualTree(content))
                    yield return obj;
            }
        }
    }

    for (int i = 0; i < childrenCount; i++)
    {
        var visualChild = VisualTreeHelper.GetChild(element, i);
        yield return visualChild;
        foreach (var visualChildren in GetVisualTree(visualChild))
        {
            yield return visualChildren;
        }
    }
}

Labels: , ,

0 comments:

Post a Comment