Stopbyte

Control Tree Hierarchy In WPF

How I can search a WPF control hierarchy for control that matches a given type or name?

1 Like

The WPF Snoop is the good to check your Apps visual tree at run time. and also to check why your code isn’t working or producing the expected results.
Another alternative would be using the free integrated Visual Studio control tree browser during debugging…

/// <param name="parent">The root ancestor, under which you want to find the item.</param>
/// <typeparam name="T">The Type of the Item to look for.</typeparam>
/// <param name="childName">Name of the Item to look for. </param>
public static T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
{    
  // Safety Check...
  if (parent == null || string.IsNullOrEmpty(childName)) return null;

  T foundChild = null;

  int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
  for (int i = 0; i < childrenCount; i++)
  {
    var child = VisualTreeHelper.GetChild(parent, i);
    
    T childType = child as T;
    if (childType == null)
    {
      foundChild = FindChild<T>(child, childName);
      if (foundChild != null) break;
    }
    else if (!string.IsNullOrEmpty(childName))
    {
      var frameworkElement = child as FrameworkElement;
      if (frameworkElement != null && frameworkElement.Name == childName)
      {
        foundChild = (T)child;
        break;
      }
    }
    else
    {
      foundChild = (T)child;
      break;
    }
  }
  return foundChild;
}

Call it like this:

var MyTextBox = UIHelper.FindChild<TextBox>(YourRootParentControl, "TextBox1");
  • You can using this name FrameworkElement.FindName(string) to find the element.
  • Given:
<UserControl ...>
    <TextBlock x:Name="myTextBlock" />
</UserControl>
  • In the code above,you could write:
`> var myTextBlock = (TextBlock)this.FindName("myTextBlock");`
  • Of course, because it’s defined using x:Name you could just reference the generated field.
    Note:This approach is also available for templates,which shows the item named several times(once the template is used).
  • If you want to find controls you can use the VisualTreeHelper;. Below is a method that uses the VisualTreeHelper to find a parent control of a specified type:
    Note: you can also use the VisualTreeHelper to find controls in other ways as well.
public static class UIHelper
{
   /// <summary>
   /// Finds a parent of a given item on the visual tree.
   /// </summary>
   /// <typeparam name="T">The type of the queried item.</typeparam>
   /// <param name="child">A direct or indirect child of the queried item.</param>
   /// <returns>The first parent item that matches the submitted type parameter. 
   /// If not matching item can be found, a null reference is being returned.</returns>
   public static T FindVisualParent<T>(DependencyObject child)
     where T : DependencyObject
   {
      // get parent item
      DependencyObject parentObject = VisualTreeHelper.GetParent(child);
      // we’ve reached the end of the tree
      if (parentObject == null) return null;
      // check if the parent matches the type we’re looking for
      T parent = parentObject as T;
      if (parent != null)
      {
         return parent;
      }
      else
      {
         // use recursion to proceed with next level
         return FindVisualParent<T>(parentObject);
      }
   }
}

Call it like this:

Window owner = UIHelper.FindVisualParent<Window>(myControl);

  • CrimsonX’s code its didn’t working with superclass types for that I corrected:
 public static T FindChild<T>(DependencyObject depObj, string childName)
   where T : DependencyObject
{
    // Confirm obj is valid. 
    if (depObj == null) return null;
    // success case
    if (depObj is T && ((FrameworkElement)depObj).Name == childName)
        return depObj as T;
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
        //DFS
        T obj = FindChild<T>(child, childName);
        if (obj != null)
            return obj;
    }
    return null;
}
  • I have a pretty piece of code that extends the DependencyObject class with a method FindChild() that will get you the child by name and type.
 public static class UIChildFinder
{
    public static DependencyObject FindChild(this DependencyObject reference, string childName, Type childType)
    {
        DependencyObject foundChild = null;
        if (reference != null)
        {
            int childrenCount = VisualTreeHelper.GetChildrenCount(reference);
            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(reference, i);
                // If the child is not of the request child type child
                if (child.GetType() != childType)
                {
                    // recursively drill down the tree
                    foundChild = FindChild(child, childName, childType);
                }
                else if (!string.IsNullOrEmpty(childName))
                {
                    var frameworkElement = child as FrameworkElement;
                    // If the child's name is set for search
                    if (frameworkElement != null && frameworkElement.Name == childName)
                    {
                        // if the child's name is of the request name
                        foundChild = child;
                        break;
                    }
                }
                else
                {
                    // child element found.
                    foundChild = child;
                    break;
                }
            }
        }
        return foundChild;
    }
}

It just use and include.