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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/974598/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 04:38:00  来源:igfitidea点击:

Find all controls in WPF Window by type

c#.netwpf

提问by Andrija

I'm looking for a way to find all controls on Window by their type,

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

for example:find all TextBoxes, find all controls implementing specific interface etc.

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

采纳答案by Bryce Kahle

This should do the trick

这应该可以解决问题

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

then you enumerate over the controls like so

然后你像这样枚举控件

foreach (TextBlock tb in FindVisualChildren<TextBlock>(window))
{
    // do something with tb here
}

回答by Oskar

Use the helper classes VisualTreeHelperor LogicalTreeHelperdepending on which treeyou're interested in. They both provide methods for getting the children of an element (although the syntax differs a little). I often use these classes for finding the first occurrence of a specific type, but you could easily modify it to find all objects of that type:

使用辅助类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;
}

回答by Oskar

And this is how it works upwards

这就是它向上工作的方式

    private T FindParent<T>(DependencyObject item, Type StopAt) where T : class
    {
        if (item is T)
        {
            return item as T;
        }
        else
        {
            DependencyObject _parent = VisualTreeHelper.GetParent(item);
            if (_parent == null)
            {
                return default(T);
            }
            else
            {
                Type _type = _parent.GetType();
                if (StopAt != null)
                {
                    if ((_type.IsSubclassOf(StopAt) == true) || (_type == StopAt))
                    {
                        return null;
                    }
                }

                if ((_type.IsSubclassOf(typeof(T)) == true) || (_type == typeof(T)))
                {
                    return _parent as T;
                }
                else
                {
                    return FindParent<T>(_parent, StopAt);
                }
            }
        }
    }

回答by Joel

This is the easiest way:

这是最简单的方法:

IEnumerable<myType> collection = control.Children.OfType<myType>(); 

where control is the root element of the window.

其中 control 是窗口的根元素。

回答by Philipp

Do note that using the VisualTreeHelper does only work on controls that derive from Visual or Visual3D. If you also need to inspect other elements (e.g. TextBlock, FlowDocument etc.), using VisualTreeHelper will throw an exception.

请注意,使用 VisualTreeHelper 仅适用于从 Visual 或 Visual3D 派生的控件。如果您还需要检查其他元素(例如 TextBlock、FlowDocument 等),使用 VisualTreeHelper 将引发异常。

Here's an alternative that falls back to the logical tree if necessary:

如果有必要,这里有一个替代方案,可以回退到逻辑树:

http://www.hardcodet.net/2009/06/finding-elements-in-wpf-tree-both-ways

http://www.hardcodet.net/2009/06/finding-elements-in-wpf-tree-both-ways

回答by Michael

To get a list of all childs of a specific type you can use:

要获取特定类型的所有子项的列表,您可以使用:

private static IEnumerable<DependencyObject> FindInVisualTreeDown(DependencyObject obj, Type type)
{
    if (obj != null)
    {
        if (obj.GetType() == type)
        {
            yield return obj;
        }

        for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type))
            {
                if (child != null)
                {
                    yield return child;
                }
            }
        }
    }

    yield break;
}

回答by David R

I found that the line, VisualTreeHelper.GetChildrenCount(depObj);, used in several examples above does not return a non-zero count for GroupBoxes, in particular, where the GroupBox contains a Grid, and the Grid contains children elements. I believe this may be because the GroupBox is not allowed to contain more than one child, and this is stored in its Content property. There is no GroupBox.Children type of property. I am sure I did not do this very efficiently, but I modified the first "FindVisualChildren" example in this chain as follows:

我发现在上面的几个示例中使用的行 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; 
                } 
            }
        }
    } 

回答by Benjamin Berry

Small change to the recursion to so you can for example find the child tab control of a tab control.

对递归的小改动,以便您可以例如找到选项卡控件的子选项卡控件。

    public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type)
    {
        if (obj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);

                if (child.GetType() == type)
                {
                    return child;
                }

                DependencyObject childReturn = FindInVisualTreeDown(child, type);
                if (childReturn != null)
                {
                    return childReturn;
                }
            }
        }

        return null;
    }

回答by Simon F

I adapted @Bryce Kahle's answer to follow @Mathias Lykkegaard Lorenzen's suggestion and use LogicalTreeHelper.

我改编了@Bryce Kahle 的回答以遵循@Mathias Lykkegaard Lorenzen 的建议并使用LogicalTreeHelper。

Seems to work okay. ;)

似乎工作正常。;)

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

(It still won't check tab controls or Grids inside GroupBoxes as mentioned by @Benjamin Berry & @David R respectively.) (Also followed @noonand's suggestion & removed the redundant child != null)

(它仍然不会检查@Benjamin Berry 和@David R 分别提到的 GroupBoxes 中的选项卡控件或网格。)(也遵循@noonand 的建议并删除了多余的孩子!= null)

回答by user1656671

Here is yet another, compact version, with the generics syntax:

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

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