By alex2k8


2009-03-11 21:08:25 8 Comments

I need to search a WPF control hierarchy for controls that match a given name or type. How can I do this?

18 comments

@Nathan Phillips 2011-09-06 12:31:17

Whilst I love recursion in general, it's not as efficient as iteration when programming in C#, so perhaps the following solution is neater than the one suggested by John Myczek? This searches up a hierarchy from a given control to find an ancestor control of a particular type.

public static T FindVisualAncestorOfType<T>(this DependencyObject Elt)
    where T : DependencyObject
{
    for (DependencyObject parent = VisualTreeHelper.GetParent(Elt);
        parent != null; parent = VisualTreeHelper.GetParent(parent))
    {
        T result = parent as T;
        if (result != null)
            return result;
    }
    return null;
}

Call it like this to find the Window containing a control called ExampleTextBox:

Window window = ExampleTextBox.FindVisualAncestorOfType<Window>();

@Demodave 2018-10-26 15:25:13

Please show an example of how to call your code

@Amir Oveisi 2017-11-21 21:17:55

This code just fixes @CrimsonX answer's bug:

 public static T FindChild<T>(DependencyObject parent, string childName)
       where T : DependencyObject
    {    
      // Confirm parent and childName are valid. 
      if (parent == null) return null;

      T foundChild = null;

      int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
      for (int i = 0; i < childrenCount; i++)
      {
        var child = VisualTreeHelper.GetChild(parent, i);
        // If the child is not of the request child type child
        T childType = child as T;
        if (childType == null)
        {
          // recursively drill down the tree
          foundChild = FindChild<T>(child, childName);

          // If the child is found, break so we do not overwrite the found child. 
          if (foundChild != null) break;
        }
        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 = (T)child;
            break;
          }

 // recursively drill down the tree
          foundChild = FindChild<T>(child, childName);

          // If the child is found, break so we do not overwrite the found child. 
          if (foundChild != null) break;


        else
        {
          // child element found.
          foundChild = (T)child;
          break;
        }
      }

      return foundChild;
    }  

You just need to continue calling the method recursively if types are matching but names don't (this happens when you pass FrameworkElement as T). otherwise it's gonna return null and that's wrong.

@Drew Noakes 2017-03-07 12:54:57

To find an ancestor of a given type from code, you can use:

[CanBeNull]
public static T FindAncestor<T>(DependencyObject d) where T : DependencyObject
{
    while (true)
    {
        d = VisualTreeHelper.GetParent(d);

        if (d == null)
            return null;

        var t = d as T;

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

This implementation uses iteration instead of recursion which can be slightly faster.

If you're using C# 7, this can be made slightly shorter:

[CanBeNull]
public static T FindAncestor<T>(DependencyObject d) where T : DependencyObject
{
    while (true)
    {
        d = VisualTreeHelper.GetParent(d);

        if (d == null)
            return null;

        if (d is T t)
            return t;
    }
}

@Neeraj 2015-04-02 15:04:21

These options already talk about traversing the Visual Tree in C#. Its possible to traverse the visual tree in xaml as well using RelativeSource markup extension. msdn

find by type

Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type <TypeToFind>}}}" 

@CrimsonX 2009-11-18 23:42:25

I combined the template format used by John Myczek and Tri Q's algorithm above to create a findChild Algorithm that can be used on any parent. Keep in mind that recursively searching a tree downwards could be a lengthy process. I've only spot-checked this on a WPF application, please comment on any errors you might find and I'll correct my code.

WPF Snoop is a useful tool in looking at the visual tree - I'd strongly recommend using it while testing or using this algorithm to check your work.

There is a small error in Tri Q's Algorithm. After the child is found, if childrenCount is > 1 and we iterate again we can overwrite the properly found child. Therefore I added a if (foundChild != null) break; into my code to deal with this condition.

/// <summary>
/// Finds a Child of a given item in the visual tree. 
/// </summary>
/// <param name="parent">A direct parent of the queried item.</param>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="childName">x:Name or Name of child. </param>
/// <returns>The first parent item that matches the submitted type parameter. 
/// If not matching item can be found, 
/// a null parent is being returned.</returns>
public static T FindChild<T>(DependencyObject parent, string childName)
   where T : DependencyObject
{    
  // Confirm parent and childName are valid. 
  if (parent == null) return null;

  T foundChild = null;

  int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
  for (int i = 0; i < childrenCount; i++)
  {
    var child = VisualTreeHelper.GetChild(parent, i);
    // If the child is not of the request child type child
    T childType = child as T;
    if (childType == null)
    {
      // recursively drill down the tree
      foundChild = FindChild<T>(child, childName);

      // If the child is found, break so we do not overwrite the found child. 
      if (foundChild != null) break;
    }
    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 = (T)child;
        break;
      }
    }
    else
    {
      // child element found.
      foundChild = (T)child;
      break;
    }
  }

  return foundChild;
}

Call it like this:

TextBox foundTextBox = 
   UIHelper.FindChild<TextBox>(Application.Current.MainWindow, "myTextBoxName");

Note Application.Current.MainWindow can be any parent window.

@Gishu 2010-03-24 02:36:56

@CrimsonX: Maybe I'm doing this wrong... I had a similar need where I needed to get to a control (ListBox) inside a ContentControl (Expander). The above code didn't work for me as is.. I had to update the above code to see if a leaf node (GetChildrenCount => 0) is a ContentControl. If yes, check if the content matches the name+type criteria.

@CrimsonX 2010-03-24 15:38:32

@Gishu - I think it should work for this purpose. Can you copy & paste your code to show how you're using the call? I would expect it should be FindChild<ListBox>(Expander myExpanderName, "myListBoxName").

@Gishu 2010-03-25 02:36:24

@CrimsonX: FindChild<ListBox>( topLevelUserControl, "myListBoxName") & topLevelUserControl > DockPanel > StackPanel > Expander > ListBox The recursion would stop at the Expander ; since GetChildrenCount() would return 0.

@CrimsonX 2010-03-25 14:44:44

@Gishu - It sounds like you're using the code as it was intended but have found a case where it doesn't completely work properly. I'm not completely familiar with why this wouldn't work properly. Feel free to post complete code in answering the question below or something like that

@Gishu 2010-04-20 08:06:44

@CrimsonX - Done. Seems that logical children need to be factored into the equation. For details.. See my post in this question..

@user336936 2010-05-10 03:39:41

Hi CrimsonX, By apply your solution, i can find my first TextBox which is generate automatically by ListBox. But how can i find specific item in my ListBox ex:the 2nd, 3rd ... item?

@kevindaub 2012-05-29 15:56:27

@CrimsonX I think I found another corner case. I was trying to find the PART_SubmenuPlaceholder in the RibbonApplicationMenuItem, but the code above was not working. To resolve it, I needed to add the following: if (name == ElementName) else { foundChild = FindChild(child, name) if (foundChild != null) break; }

@Eric Ouellet 2014-02-06 16:26:02

Please be carefull, there is a bug or more in the answer. It will stop as soon as it will reach a child of the searched type. I think you should consider/prioritize other answers.

@WPFKK 2014-06-30 22:22:15

Snoop is your best shot it is pretty much similar to firebug for asp.net/html

@Amir Oveisi 2017-11-21 21:09:09

This code is great, but it won't work if you are not looking for a specific type of element, for example if you pass FrameworkElement as T, it's gonna return null as soon as first loop ends. so you gonna need do some modifications.

@UrbanEsc 2012-02-10 14:23:23

If you want to find ALL controls of a specific type, you might be interested in this snippet too

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject parent) 
        where T : DependencyObject
    {
        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);

            var childType = child as T;
            if (childType != null)
            {
                yield return (T)child;
            }

            foreach (var other in FindVisualChildren<T>(child))
            {
                yield return other;
            }
        }
    }

@Klaus Nji 2012-05-30 21:09:23

Good one but ensure control is loaded otherwise GetChildrenCount will return 0.

@Massimiliano Kraus 2016-10-26 15:19:54

@UrbanEsc, why do you cast child a second time? If you have childType of type T, you can write inside the if: yield return childType... no?

@UrbanEsc 2017-10-02 13:21:08

@MassimilianoKraus Hey, sorry for the late response, but you are right. I attribute it to me rewriting this snippet several times, and thus this might be a fragment of a different check

@Gishu 2010-04-20 08:10:18

My extensions to the code.

  • Added overloads to find one child by type, by type and criteria (predicate), find all children of type which meet the criteria
  • the FindChildren method is an iterator in addition to being an extension method for DependencyObject
  • FindChildren walks logical sub-trees also. See Josh Smith's post linked in the blog post.

Source: https://code.google.com/p/gishu-util/source/browse/#git%2FWPF%2FUtilities

Explanatory blog post : http://madcoderspeak.blogspot.com/2010/04/wpf-find-child-control-of-specific-type.html

@cod3monk3y 2014-07-19 19:41:29

-1 Exactly what I was about to implement (predicate, iterator, and extension method), but there's a 404 on the source link. Will change to +1 if code is included here, or source link is fixed!

@Gishu 2014-07-21 10:06:55

@cod3monk3y - Git migration killed the link it seems :) Here you go.. code.google.com/p/gishu-util/source/browse/…

@Jayasri 2015-03-23 05:57:03

Try this

<TextBlock x:Name="txtblock" FontSize="24" >Hai Welcom to this page
</TextBlock>

Code Behind

var txtblock = sender as Textblock;
txtblock.Foreground = "Red"

@Tim Pohlmann 2015-09-09 15:54:59

Here is a solution that uses a flexible predicate:

public static DependencyObject FindChild(DependencyObject parent, Func<DependencyObject, bool> predicate)
{
    if (parent == null) return null;

    int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < childrenCount; i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);

        if (predicate(child))
        {
            return child;
        }
        else
        {
            var foundChild = FindChild(child, predicate);
            if (foundChild != null)
                return foundChild;
        }
    }

    return null;
}

You can for example call it like this:

var child = FindChild(parent, child =>
{
    var textBlock = child as TextBlock;
    if (textBlock != null && textBlock.Name == "MyTextBlock")
        return true;
    else
        return false;
}) as TextBlock;

@VB Guy 2014-08-20 15:45:01

I have a sequence function like this (which is completely general):

    public static IEnumerable<T> SelectAllRecursively<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> func)
    {
        return (items ?? Enumerable.Empty<T>()).SelectMany(o => new[] { o }.Concat(SelectAllRecursively(func(o), func)));
    }

Getting immediate children:

    public static IEnumerable<DependencyObject> FindChildren(this DependencyObject obj)
    {
        return Enumerable.Range(0, VisualTreeHelper.GetChildrenCount(obj))
            .Select(i => VisualTreeHelper.GetChild(obj, i));
    }

Finding all children down the hiararchical tree:

    public static IEnumerable<DependencyObject> FindAllChildren(this DependencyObject obj)
    {
        return obj.FindChildren().SelectAllRecursively(o => o.FindChildren());
    }

You can call this on the Window to get all controls.

After you have the collection, you can use LINQ (i.e. OfType, Where).

@Shawn Nelson 2011-06-06 23:26:57

exciton80... I was having a problem with your code not recursing through usercontrols. It was hitting the Grid root and throwing an error. I believe this fixes it for me:

public static object[] FindControls(this FrameworkElement f, Type childType, int maxDepth)
{
    return RecursiveFindControls(f, childType, 1, maxDepth);
}

private static object[] RecursiveFindControls(object o, Type childType, int depth, int maxDepth = 0)
{
    List<object> list = new List<object>();
    var attrs = o.GetType().GetCustomAttributes(typeof(ContentPropertyAttribute), true);
    if (attrs != null && attrs.Length > 0)
    {
        string childrenProperty = (attrs[0] as ContentPropertyAttribute).Name;
        if (String.Equals(childrenProperty, "Content") || String.Equals(childrenProperty, "Children"))
        {
            var collection = o.GetType().GetProperty(childrenProperty).GetValue(o, null);
            if (collection is System.Windows.Controls.UIElementCollection) // snelson 6/6/11
            {
                foreach (var c in (IEnumerable)collection)
                {
                    if (c.GetType().FullName == childType.FullName)
                        list.Add(c);
                    if (maxDepth == 0 || depth < maxDepth)
                        list.AddRange(RecursiveFindControls(
                            c, childType, depth + 1, maxDepth));
                }
            }
            else if (collection != null && collection.GetType().BaseType.Name == "Panel") // snelson 6/6/11; added because was skipping control (e.g., System.Windows.Controls.Grid)
            {
                if (maxDepth == 0 || depth < maxDepth)
                    list.AddRange(RecursiveFindControls(
                        collection, childType, depth + 1, maxDepth));
            }
        }
    }
    return list.ToArray();
}

@El Zorko 2011-03-06 13:03:18

Since the question is general enough that it might attract people looking for answers to very trivial cases: if you just want a child rather than a descendant, you can use Linq:

private void ItemsControlItem_Loaded(object sender, RoutedEventArgs e)
{
    if (SomeCondition())
    {
        var children = (sender as Panel).Children;
        var child = (from Control child in children
                 where child.Name == "NameTextBox"
                 select child).First();
        child.Focus();
    }
}

or of course the obvious for loop iterating over Children.

@John Myczek 2009-03-11 21:28:37

You can use the VisualTreeHelper to find controls. Below is a method that uses the VisualTreeHelper to find a parent control of a specified type. You can 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);

@Demodave 2018-10-26 15:13:39

How do you get or what is myControl?

@exciton80 2010-10-20 10:17:24

Here's my code to find controls by Type while controlling how deep we go into the hierarchy (maxDepth == 0 means infinitely deep).

public static class FrameworkElementExtension
{
    public static object[] FindControls(
        this FrameworkElement f, Type childType, int maxDepth)
    {
        return RecursiveFindControls(f, childType, 1, maxDepth);
    }

    private static object[] RecursiveFindControls(
        object o, Type childType, int depth, int maxDepth = 0)
    {
        List<object> list = new List<object>();
        var attrs = o.GetType()
            .GetCustomAttributes(typeof(ContentPropertyAttribute), true);
        if (attrs != null && attrs.Length > 0)
        {
            string childrenProperty = (attrs[0] as ContentPropertyAttribute).Name;
            foreach (var c in (IEnumerable)o.GetType()
                .GetProperty(childrenProperty).GetValue(o, null))
            {
                if (c.GetType().FullName == childType.FullName)
                    list.Add(c);
                if (maxDepth == 0 || depth < maxDepth)
                    list.AddRange(RecursiveFindControls(
                        c, childType, depth + 1, maxDepth));
            }
        }
        return list.ToArray();
    }
}

@Demodave 2018-10-26 15:20:43

Please show an example on how to call this.

@andresp 2010-06-10 13:57:32

I edited CrimsonX's code as it was not working with superclass types:

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;
}

@Tim Pohlmann 2015-09-09 15:32:30

If you pass this method a DependencyObject that is not a FrameworkElement it can throw an Exception. Also using GetChildrenCount on every iteration of the for loop sounds like a bad idea.

@andresp 2015-09-10 11:30:57

well, this is from 5 years ago, so I don't even know if it works anymore :)

@Tim Pohlmann 2015-09-10 11:44:30

I just mentioned it, because I stumbled upon it and other could as well ;)

@andresp 2015-09-10 12:18:10

@TimPohlmann yes, that might be useful. thanks!

@Tri Q Tran 2009-10-01 00:52:54

I may be just repeating everyone else but I do have a pretty piece of code that extends the DependencyObject class with a method FindChild() that will get you the child by type and name. Just include and use.

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;
    }
}

Hope you find it useful.

@CrimsonX 2009-11-19 02:13:45

Per my post above, there is a small implementation error in your code: stackoverflow.com/questions/636383/wpf-ways-to-find-controls‌​/…

@Demodave 2018-10-26 15:23:23

Please show an example on how to call this

@Drew Noakes 2009-09-25 12:48:51

You can also find an element by name using FrameworkElement.FindName(string).

Given:

<UserControl ...>
    <TextBlock x:Name="myTextBlock" />
</UserControl>

In the code-behind file, 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, but perhaps you want to look it up dynamically rather than statically.

This approach is also available for templates, in which the named item appears multiple times (once per usage of the template).

@brian buck 2011-07-19 22:12:19

For this to work you don't necessarily have to add the "x:" to the name attribute.

@Matt 2018-04-25 07:55:41

This doesnt seem to always work. I have UserControls which are combined together programmatically in nested grids as the contents of a properties window. CrimsonX's answer works fine however.

@Sorensen 2018-04-30 14:04:16

This won't work for elements within ItemControls, ListBoxes, etc.

@Philipp 2009-06-25 09:40:10

This will dismiss some elements - you should extend it like this in order to support a wider array of controls. For a brief discussion, have a look here

 /// <summary>
 /// Helper methods for UI-related tasks.
 /// </summary>
 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 TryFindParent<T>(DependencyObject child)
     where T : DependencyObject
   {
     //get parent item
     DependencyObject parentObject = GetParentObject(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 TryFindParent<T>(parentObject);
     }
   }

   /// <summary>
   /// This method is an alternative to WPF's
   /// <see cref="VisualTreeHelper.GetParent"/> method, which also
   /// supports content elements. Do note, that for content element,
   /// this method falls back to the logical tree of the element!
   /// </summary>
   /// <param name="child">The item to be processed.</param>
   /// <returns>The submitted item's parent, if available. Otherwise
   /// null.</returns>
   public static DependencyObject GetParentObject(DependencyObject child)
   {
     if (child == null) return null;
     ContentElement contentElement = child as ContentElement;

     if (contentElement != null)
     {
       DependencyObject parent = ContentOperations.GetParent(contentElement);
       if (parent != null) return parent;

       FrameworkContentElement fce = contentElement as FrameworkContentElement;
       return fce != null ? fce.Parent : null;
     }

     //if it's not a ContentElement, rely on VisualTreeHelper
     return VisualTreeHelper.GetParent(child);
   }
}

@Drew Noakes 2009-09-25 12:51:47

By convention, I would expect any Try* method to return bool and have an out parameter that returns the type in question, as with: bool IDictionary.TryGetValue(TKey key, out TValue value)

@ANeves 2014-09-15 19:13:17

@DrewNoakes what do you suggest Philipp to call it, then? Also, even with such an expectation I find his code both clear and clear to use.

@Drew Noakes 2014-09-16 11:07:26

@ANeves, in this case I would just call it FindParent. This name to me implies that it could return null. The Try* prefix is used throughout the BCL in the way I describe above. Also note that most of the other answers here use the Find* naming convention. It's only a minor point though :)

Related Questions

Sponsored Content

35 Answered Questions

[SOLVED] What is the correct way to create a single-instance WPF application?

  • 2008-08-21 00:33:59
  • Nidonocu
  • 175422 View
  • 593 Score
  • 35 Answer
  • Tags:   c# .net wpf mutex

33 Answered Questions

[SOLVED] How to exclude a directory in find . command

  • 2010-11-17 22:57:02
  • helion3
  • 801542 View
  • 1069 Score
  • 33 Answer
  • Tags:   linux shell find

67 Answered Questions

[SOLVED] Metadata file '.dll' could not be found

41 Answered Questions

[SOLVED] How do I find all files containing specific text on Linux?

14 Answered Questions

[SOLVED] In WPF, what are the differences between the x:Name and Name attributes?

18 Answered Questions

[SOLVED] How can I exclude all "permission denied" messages from "find"?

4 Answered Questions

[SOLVED] How to get controls in WPF to fill available space?

10 Answered Questions

[SOLVED] WPF image resources

14 Answered Questions

[SOLVED] WPF User Control Parent

  • 2008-11-19 18:13:47
  • donniefitz2
  • 148389 View
  • 176 Score
  • 14 Answer
  • Tags:   c# .net wpf

2 Answered Questions

How can I find all controls within a control(WPF, C#)?

  • 2010-08-03 12:47:13
  • Marcelo Z
  • 4767 View
  • 1 Score
  • 2 Answer
  • Tags:   wpf

Sponsored Content