【问题标题】:Foreach loop for disposing controls skipping iterations用于处理跳过迭代的控件的 Foreach 循环
【发布时间】:2016-01-29 11:50:28
【问题描述】:

创建文本框的代码...

private void btnAddIncrement_Click(object sender, EventArgs e)
{              
    SmartTextBox dynamictextbox = new SmartTextBox();

        dynamictextbox.BackColor = Color.Bisque;
        dynamictextbox.Width = this.tbWidth;
        dynamictextbox.Left = (sender as Button).Right + this.lastLeft;
    dynamictextbox.K = "Test";

    this.lastLeft = this.lastLeft + this.tbWidth;
    dynamictextbox.Top = btnAddStart.Top;
    this.Controls.Add(dynamictextbox);              
}

删除所有文本框的代码。

foreach (Control c in this.Controls)
{

    if (c.GetType() == typeof(BnBCalculator.SmartTextBox))
    {
        count++;
        //MessageBox.Show((c as SmartTextBox).K.ToString());
        c.Dispose();
    }
   // else { MessageBox.Show("not txtbox"); }

}

当我单击 btnAddIncrement 时,我按预期得到以下内容...

但是当我点击重置时,它会错过第二个文本框。见下文...

不知道这里发生了什么,但无论我添加多少文本框都是一样的。它总是错过第二个盒子。

【问题讨论】:

标签: c# winforms


【解决方案1】:

您应该使用反向标准 for 循环从其容器中处理 SmartTextBoxes

for(int x = this.Controls.Count - 1; x >= 0; x--)
{
    BnBCalculator.SmartTextBox c = this.Controls[x] as BnBCalculator.SmartTextBox;
    if (c != null)
    {
        count++;
        c.Dispose();
    }
}

According to this question/answer 你不需要从容器中删除它们,当然这避免了两个循环(显式或隐式)。同样在接受的答案中,您可以看到您的代码每两个跳过一个控件的原因。

if (parent != null) 
{ 
    parent.Controls.Remove(this); 
}

您要处置的控件已从您正在迭代的集合中删除。 (不清楚为什么这不会引发标准异常)。

而是使用简单的 for 反向循环,避免在有序访问要处理的控件时出现任何问题。

【讨论】:

    【解决方案2】:

    当您从this.Controls 中删除一个项目时,集合会被修改,因此下一个项目不是您所期望的。哟应该将this.Controls 复制到一个新列表中。例如,您可以使用ToArray 复制this.Controls

    foreach (Control c in this.Controls.ToArray())
    {
        ...
    }
    

    【讨论】:

      【解决方案3】:

      您的删除代码不正确,因为您正在通过调用 Dispose() 修改 Controls 集合,这就是您跳过控件的原因。

      删除特定类型的最简单的方法是执行以下操作:

      var smartTbs = this.Controls.OfType<BnBCalculator.SmartTextBox>().ToList();
      smartTbs.ForEach(x => x.Dispose());
      

      【讨论】:

        【解决方案4】:

        您必须首先从 Form.Controls 中删除控件,然后再将其处理掉。

        var controlsToRemove = new List<Control>();
        foreach (Control c in this.Controls)
        {
            if (c is BnBCalculator.SmartTextBox) 
                controlsToRemove.Add(c);
        }
        
        foreach (Control c in controlsToRemove)
        {
            Controls.Remove(c);
        }
        

        【讨论】:

          【解决方案5】:

          尝试先选择所有 SmartTextBox 控件,然后将它们放置在另一个循环中。伪代码:

              SmartTextBoxes = Select From this.Controls Where (c.GetType() == typeof(BnBCalculator.SmartTextBox));
              foreach(stb in SmartTextBoxes) { stb.Dispose(); }
          

          【讨论】:

          • 你可以使用 LINQ 的 OfType&lt;T&gt;() 方法。
          • 没错。但是在 IDE 之外编写正确的 LINQ 表达式有点困难。所以我刚刚写了“伪代码”,牢记LINQ。
          猜你喜欢
          • 2019-05-23
          • 2018-01-01
          • 1970-01-01
          • 2023-03-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多