How can I find WPF controls by name or type?

后端 未结 18 2997
庸人自扰
庸人自扰 2020-11-21 04:23

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

相关标签:
18条回答
  • 2020-11-21 04:52

    Try this

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

    Code Behind

    var txtblock = sender as Textblock;
    txtblock.Foreground = "Red"
    
    0 讨论(0)
  • 2020-11-21 04:53

    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;
    }
    
    0 讨论(0)
  • 2020-11-21 04:53

    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.

    0 讨论(0)
  • 2020-11-21 04:54

    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>();
    
    0 讨论(0)
  • 2020-11-21 04:54

    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();
    }
    
    0 讨论(0)
  • 2020-11-21 04:59

    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

    0 讨论(0)
提交回复
热议问题