Search code examples
c#.netwpfvisual-tree

Find visual children recursively is not adding the root object in WPF?


I have the following implementation to get all the children in a VisualTree of a type T:

    IEnumerable<T> FindVisualChildrenRecurse<T>(DependencyObject root) where T : DependencyObject
    {
        if (root != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(root, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }

                foreach (T childOfChild in FindVisualChildrenRecurse<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }

I call this method using the following:

IEnumerable<TextBlock> textBlocks = FindVisualChildren<TextBlock>(
    button.Content as DependencyObject);

However, this implementation does not work fine when the root dependendy object is of type T. Imagine that we want to find all TextBlocks in a VisualTree

Content
  StackPanel
      TextBlock
      Image

In this case, the implementation finds successfully the TextBlock. However, if I have this other layout:

Content
    TextBlock

The implementation does not include the root object, so it does not find the TextBlock. How can I re-write the method and include the root object?


Solution

  • I needed to yield return the root before looping. This implementation makes the fix:

        IEnumerable<T> FindVisualChildren<T>(DependencyObject dependencyObject) where T : DependencyObject
        {
            if (dependencyObject == null)
                yield break;
    
            if (dependencyObject is T)
                yield return (T)dependencyObject;
    
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(dependencyObject, i);
                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }