按类型查找WPF窗口中的所有控件

And*_*ija 213 .net c# wpf

我正在寻找一种方法来查找Window类型的所有控件,

例如:查找全部TextBoxes,找到实现特定接口的所有控件等.

Bry*_*hle 417

这应该可以解决问题

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

            foreach (T childOfChild in FindVisualChildren<T>(child))
            {
                yield return childOfChild;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你像这样枚举控件

foreach (TextBlock tb in FindVisualChildren<TextBlock>(window))
{
    // do something with tb here
}
Run Code Online (Sandbox Code Playgroud)

  • 注意:如果您试图让它工作并发现您的Window(例如)有0个可视子项,请尝试在Loaded事件处理程序中运行此方法.如果在构造函数中运行它(甚至在InitializeComponent()之后),则尚未加载可视子项,并且它将不起作用. (66认同)
  • 从VisualTreeHelper切换到LogicalTreeHelpers也会导致包含不可见元素. (23认同)
  • 不是行"孩子!= null &&孩子是T"多余?它应该不只是读"孩子是T" (11认同)
  • 我会将它变成一个扩展方法,只需在 `DependencyObject` =&gt; `this DependencyObject depObj` 之前插入一个 `this` (2认同)
  • @JohannesWanzek不要忘记您还需要更改在子项上调用它的位: foreach(ChildofChild.FindVisualChildren&lt;T&gt;()){bla bla bla} (2认同)
  • `return;` 不会编译。 (2认同)

Joe*_*oel 63

这是最简单的方法:

IEnumerable<myType> collection = control.Children.OfType<myType>(); 
Run Code Online (Sandbox Code Playgroud)

其中control是窗口的根元素.

  • 这不能回答被问到的问题.它只返回一级深度的子​​控件. (64认同)

Sim*_*n F 21

我改编了@Bryce Kahle的回答来关注@Mathias Lykkegaard Lorenzen的建议并使用LogicalTreeHelper.

好像工作还可以.;)

    public static IEnumerable<T> FindLogicalChildren<T> ( DependencyObject depObj ) where T : DependencyObject {
        if( depObj != null ) {
            foreach( object rawChild in LogicalTreeHelper.GetChildren( depObj ) ){
                if( rawChild is DependencyObject ) {
                    DependencyObject child = (DependencyObject)rawChild;
                    if( child is T ) {
                        yield return (T)child;
                    }

                    foreach( T childOfChild in FindLogicalChildren<T>( child ) ) {
                        yield return childOfChild;
                    }
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

(它仍然不会检查@Benjamin Berry和@David R分别提到的GroupBox中的制表符控件或网格.)(同时遵循@ noonand的建议并删除多余的孩子!= null)


Osk*_*kar 13

使用辅助类VisualTreeHelperLogicalTreeHelper取决于您感兴趣的.它们都提供了获取元素子元素的方法(尽管语法略有不同).我经常使用这些类来查找特定类型的第一个匹配项,但您可以轻松地修改它以查找该类型的所有对象:

public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type)
{
    if (obj != null)
    {
        if (obj.GetType() == type)
        {
            return obj;
        }

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            DependencyObject childReturn = FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type);
            if (childReturn != null)
            {
                return childReturn;
            }
        }
    }

    return null;
}
Run Code Online (Sandbox Code Playgroud)


小智 9

我发现上面几个例子中使用的行VisualTreeHelper.GetChildrenCount(depObj);不会返回GroupBox的非零计数,特别是GroupBox包含Grid,Grid包含子元素.我相信这可能是因为GroupBox不允许包含多个子节点,并且它存储在其Content属性中.没有GroupBox.Children类型的属性.我确信我没有非常有效地执行此操作,但我修改了此链中的第一个"FindVisualChildren"示例,如下所示:

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

                if (child is GroupBox)
                {
                    GroupBox gb = child as GroupBox;
                    Object gpchild = gb.Content;
                    if (gpchild is T)
                    {
                        yield return (T)child; 
                        child = gpchild as T;
                    }
                }

                foreach (T childOfChild in FindVisualChildren<T>(child)) 
                { 
                    yield return childOfChild; 
                } 
            }
        }
    } 
Run Code Online (Sandbox Code Playgroud)


use*_*671 6

这是另一个紧凑版本,具有泛型语法:

    public static IEnumerable<T> FindLogicalChildren<T>(DependencyObject obj) where T : DependencyObject
    {
        if (obj != null) {
            if (obj is T)
                yield return obj as T;

            foreach (DependencyObject child in LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>()) 
                foreach (T c in FindLogicalChildren<T>(child)) 
                    yield return c;
        }
    }
Run Code Online (Sandbox Code Playgroud)