C# WPF:如何遍历窗口中的所有控件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/874380/
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-05 05:01:00  来源:igfitidea点击:

WPF: How do I loop through the all controls in a window?

c#.netwpf

提问by Tony

How do I loop through the all controls in a window in WPF?

如何遍历 WPF 窗口中的所有控件?

采纳答案by abmv

Class to get a list of all the children's components of a control:

类以获取控件的所有子组件的列表:

class Utility
    {
        private static StringBuilder sbListControls;

        public static StringBuilder GetVisualTreeInfo(Visual element)
        {
            if (element == null)
            {
                throw new ArgumentNullException(String.Format("Element {0} is null !", element.ToString()));
            }

            sbListControls = new StringBuilder();

            GetControlsList(element, 0);

            return sbListControls;
        }

        private static void GetControlsList(Visual control, int level)
        {
            const int indent = 4;
            int ChildNumber = VisualTreeHelper.GetChildrenCount(control);

            for (int i = 0; i <= ChildNumber - 1; i++)
            {
                Visual v = (Visual)VisualTreeHelper.GetChild(control, i);

                sbListControls.Append(new string(' ', level * indent));
                sbListControls.Append(v.GetType());
                sbListControls.Append(Environment.NewLine);

                if (VisualTreeHelper.GetChildrenCount(v) > 0)
                {
                    GetControlsList(v, level + 1);
                }
            }
        }
    } 

回答by Julen

I found this in the MSDN documenationso it helps.

我在MSDN 文档中找到了这个,所以它有帮助。

// Enumerate all the descendants of the visual object.
static public void EnumVisual(Visual myVisual)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++)
    {
        // Retrieve child visual at specified index value.
        Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i);

        // Do processing of the child visual object.

        // Enumerate children of the child visual object.
        EnumVisual(childVisual);
    }
}

Looks simpler to me. I used it to find textboxes in a form and clear their data.

对我来说看起来更简单。我用它来查找表单中的文本框并清除它们的数据。

回答by dodgy_coder

A slight variation on the MSDN answer ... just pass in an empty List of Visual objects into it and your collection will be populated with all the child visuals:

MSDN 答案略有不同……只需将一个空的 Visual 对象列表传入其中,您的集合将填充所有子视觉对象:

/// <summary>
/// Enumerate all the descendants (children) of a visual object.
/// </summary>
/// <param name="parent">Starting visual (parent).</param>
/// <param name="collection">Collection, into which is placed all of the descendant visuals.</param>
public static void EnumVisual(Visual parent, List<Visual> collection)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    {
        // Get the child visual at specified index value.
        Visual childVisual = (Visual)VisualTreeHelper.GetChild(parent, i);

        // Add the child visual object to the collection.
        collection.Add(childVisual);

        // Recursively enumerate children of the child visual object.
        EnumVisual(childVisual, collection);
    }
}

回答by BrainSlugs83

This way is superior to the MSDN method, in that it's reusable, and it allows early aborting of the loop (i.e. via, break;, etc.) -- it optimizes the for loop in that it saves a method call for each iteration -- and it also lets you use regular for loops to loop through a Visual's children, or even recurse it's children and it's grand children -- so it's much simpler to consume.

这种方式优于 MSDN 方法,因为它是可重用的,并且它允许提前中止循环(即通过break;,等)——它优化了 for 循环,因为它为每次迭代保存了一个方法调用——并且它还允许您使用常规 for 循环来遍历 Visual 的子项,甚至递归它的子项和孙子项——因此使用起来要简单得多。

To consume it, you can just write a regular foreach loop (or even use LINQ):

要使用它,您只需编写一个常规的 foreach 循环(甚至使用 LINQ):

foreach (var ctrl in myWindow.GetChildren())
{
    // Process children here!
}

Or if you don't want to recurse:

或者,如果您不想递归:

foreach (var ctrl in myWindow.GetChildren(false))
{
    // Process children here!
}

To make it work, you just need put this extension method into any static class, and then you'll be able to write code like the above anytime you like:

为了让它工作,你只需要把这个扩展方法放到任何静态类中,然后你就可以随时编写像上面这样的代码:

public static IEnumerable<Visual> GetChildren(this Visual parent, bool recurse = true)
{
    if (parent != null)
    {
        int count = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < count; i++)
        {
            // Retrieve child visual at specified index value.
            var child = VisualTreeHelper.GetChild(parent, i) as Visual;

            if (child != null)
            {
                yield return child;

                if (recurse)
                {
                    foreach (var grandChild in child.GetChildren(true))
                    {
                        yield return grandChild;
                    }
                }
            }
        }
    }
}

Also, if you don't like recursion being on by default, you can change the extension method's declaration to have recurse = falsebe the default behavior.

此外,如果您不喜欢默认启用递归,您可以将扩展方法的声明更改recurse = false为默认行为。

回答by Rickey

I've used the following to get all controls.

我使用以下内容来获取所有控件。

    public static IList<Control> GetControls(this DependencyObject parent)
    {            
        var result = new List<Control>();
        for (int x = 0; x < VisualTreeHelper.GetChildrenCount(parent); x++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(parent, x);
            var instance = child as Control;

            if (null != instance)
                result.Add(instance);

            result.AddRange(child.GetControls());
        } 
        return result;
    }