遍历表单上的所有控件,甚至是组框中的控件

RRM*_*RRM 19 c# groupbox

我想在我的表单上的所有文本框中添加一个事件:

foreach (Control C in this.Controls)
{
    if (C.GetType() == typeof(System.Windows.Forms.TextBox))
    {
        C.TextChanged += new EventHandler(C_TextChanged);
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是它们存储在几个组框中,而我的循环看不到它们.我可以单独循环遍历每个组框的控件,但是可以在一个循环中以简单的方式完成所有操作吗?

Oli*_*bes 32

ControlsForms和容器控件的集合仅包含直接子项.为了获得所有控件,您需要遍历控件树并递归地应用此操作

private void AddTextChangedHandler(Control parent)
{
    foreach (Control c in parent.Controls)
    {
        if (c.GetType() == typeof(TextBox)) {
            c.TextChanged += new EventHandler(C_TextChanged);
        } else {
            AddTextChangedHandler(c);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:表单也是(间接)派生​​的Control,所有控件都有一个Controls集合.所以你可以在你的表单中调用这样的方法:

AddTextChangedHandler(this);
Run Code Online (Sandbox Code Playgroud)

更通用的解决方案是创建一个递归方法,以递归方式将操作应用于所有控件.在静态类(例如WinFormsExtensions)中添加此方法:

public static void ForAllControls(this Control parent, Action<Control> action)
{
    foreach (Control c in parent.Controls) {
        action(c);
        ForAllControls(c, action);
    }
}
Run Code Online (Sandbox Code Playgroud)

静态类命名空间必须是"可见的",即using如果它在另一个命名空间中,则添加适当的声明.

然后你就可以这样称呼它,this表格在哪里; 您还可以替换this其嵌套控件必须受影响的窗体或控件变量:

this.ForAllControls(c =>
{
    if (c.GetType() == typeof(TextBox)) {
        c.TextChanged += C_TextChanged;
    }
});
Run Code Online (Sandbox Code Playgroud)


Ser*_*rvy 13

一些简单的通用工具使这个问题变得非常简单.我们可以创建一个简单的方法来遍历整个控件的树,返回其所有子节点的序列,所有子节点等等,覆盖所有控件,而不仅仅是固定深度.我们可以使用递归,但通过避免递归它会表现得更好.

public static IEnumerable<Control> GetAllChildren(this Control root)
{
    var stack = new Stack<Control>();
    stack.Push(root);

    while (stack.Any())
    {
        var next = stack.Pop();
        foreach (Control child in next.Controls)
            stack.Push(child);
        yield return next;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用这个我们可以得到所有的孩子,过滤掉我们需要的类型,然后非常容易地附加处理程序:

foreach(var textbox in GetAllChildren().OfType<Textbox>())
    textbox.TextChanged += C_TextChanged;
Run Code Online (Sandbox Code Playgroud)


Geo*_*org 7

试试这个

AllSubControls(this).OfType<TextBox>().ToList()
    .ForEach(o => o.TextChanged += C_TextChanged);
Run Code Online (Sandbox Code Playgroud)

AllSubControls在哪里

private static IEnumerable<Control> AllSubControls(Control control)
    => Enumerable.Repeat(control, 1)
       .Union(control.Controls.OfType<Control>()
                              .SelectMany(AllSubControls)
             );
Run Code Online (Sandbox Code Playgroud)

LINQ很棒!


chr*_*her 1

正如您所说,您必须更深入地了解表单中的每个元素。不幸的是,这意味着使用嵌套循环。

在第一个循环中,循环遍历每个元素。如果元素的类型为 GroupBox,那么您知道在继续之前需要循环遍历 groupbox 内的每个元素;否则照常添加事件。

您似乎对 C# 有很好的掌握,所以我不会给您任何代码;纯粹是为了确保您掌握解决问题所涉及的所有重要概念:)