通过文本框中的控件的Foreach循环不返回

本文关键字:Foreach 循环 返回 控件 文本 | 更新日期: 2023-09-27 18:11:55

我以前在另一个程序中使用过这段代码,但是现在我很难理解为什么它不会在第二行之后运行代码。

foreach (Control c in Controls)
    if (c.GetType() == typeof(TextBox)) //doesn't run any further
    {
        if ((string)c.Tag == "Filled")
        {
            ...
        }
        ...
    }

我要么错过了一些小细节,要么其他地方不正确。什么好主意吗?

编辑:我的文本框在面板内。

通过文本框中的控件的Foreach循环不返回

当您调用Control.Controls时,它将只返回最外层的控件。它不会递归地下降到任何包含其他控件的容器控件。

如果控件在另一个容器中,则需要使用该容器的.Controls属性。

或者,您可以通过编写一个方法来一般化它,以递归地返回父控件及其所有子控件,如下所示:

public IEnumerable<Control> AllControls(Control container)
{
    foreach (Control control in container.Controls)
    {
        yield return control;
        foreach (var innerControl in AllControls(control))
            yield return innerControl;
    }
}

你可以用它来代替Control。控件如下:

private void test() // Assuming this is a member of a Form other class derived from Control
{
    var textboxesWithFilledTag = 
        AllControls(this).OfType<TextBox>()
        .Where(tb => (string) tb.Tag == "Filled");
    foreach (var textbox in textboxesWithFilledTag)
        Debug.WriteLine(textbox.Text);
}

正如评论所说,我假设test()方法是您的Form或派生自Control的另一个类的成员。如果不是,则必须将父控件传递给它:

private void test(Control container)
{
    var textboxesWithFilledTag = 
        AllControls(container).OfType<TextBox>()
        .Where(tb => (string) tb.Tag == "Filled");
    foreach (var textbox in textboxesWithFilledTag)
        Debug.WriteLine(textbox.Text);
}

以下方法与上面的方法具有相同的结果,供参考(并且更具可读性):

private void test(Control container)
{
    foreach (var textbox in AllControls(container).OfType<TextBox>())
        if ((string)textbox.Tag == "Filled")
            Debug.WriteLine(textbox.Text);
}

对于您的代码,按钮单击处理程序可能看起来像这样:
void button1_Click(object sender, EventArgs e)
{
    foreach (var c in AllControls(this).OfType<TextBox>())
    {
        if ((string) c.Tag == "Filled")
        {
            // Here is where you put your code to do something with Textbox 'c'
        }
    }
}

注意,您当然还需要AllControls()方法。

这样做可能更简单:

foreach ( TextBox tb in this.Controls.OfType<TextBox>()) 
{
    if ((string)tb.Tag == "Filled")
    // .....
}

要获取所有控件(不仅仅是表单的直接子控件),您可以使用这个递归Linq

Func<Control, IEnumerable<Control>> allControls = null;
allControls = c => new Control[] { c }
                   .Concat(c.Controls.Cast<Control>()
                                     .SelectMany(x=>allControls(x)));
现在你可以过滤文本框了
var tbs = allControls(this).OfType<TextBox>()
            .Where(t=>(string)t.Tag=="Filled")
            .ToList();

最好使用if (c is TextBox)。此外,如果您想知道代码中断的原因,请使用try/catch

我建议使用以下语法:

foreach (Control c in Controls)
    if (c is TextBox)

是否自己设置标签属性?这是一个string类型的属性。所以你可以试试:

if (c.Tag == "Filled")
{
    Console.WriteLine(c.Name);
}

如果你想检查文本框是否为空,那么你可以简单地试试:

if (c.Text.Trim().Length == 0)
{
 Console.WriteLine(c.Name);
}