C#中的foreach控制语句如何跳过某些控件?

5

我有以下循环来删除我的C# Windows Forms应用程序中的按钮。唯一的问题是它会跳过每隔一个按钮。我该如何从我的表单中删除所有按钮控件?

foreach (Control cntrl in Controls)
{
    if(cntrl.GetType() == typeof(Button))
    {
        Controls.Remove(cntrl);
        cntrl.Dispose();
    }
}

4
没有检查,但我预期这段代码会产生一个异常,因为你不能在循环遍历(Controls)时修改集合。 - default locale
我在执行过程中和错误列表中都没有收到任何错误提示。你有什么建议? - Altimus Prime
这段代码会抛出无效操作异常,也许你已经在任何父方法中使用try和catch包装了这段代码。 - Sriram Sakthivel
我很高兴能够追踪到这个问题。我遇到了完全相同的问题,一直在寻找解决方案,花费了一些时间才找到正确的搜索词。实际上,即使没有try和catch,它也不会给出错误,我同意这很奇怪。 - user2596213
我发现@defaultlocale和其他评论者提出的问题已经在为什么ControlCollection不会抛出InvalidOperationException?中被问到过。我已经在那个问题上删除了我的评论,并将它们重新发布为答案。我在那个答案中链接了这个问题,所以这个问题至少会在右侧的Linked部分中始终出现。 - Lance U. Matthews
3个回答

11

我认为这种方式更易读:

var controlsToRemove = Controls.OfType<Button>().ToArray();
foreach (var control in controlsToRemove)
{
    Controls.Remove(control);
    cntrl.Dispose();
}

调用 ToArray() 会创建一个新的具体集合,这样您就可以枚举其中一个并修改另一个。


2

您很惊讶这不会给您带来错误,因为您在迭代过程中修改了集合。请使用一个for循环并从末尾开始:

for (int ii = Controls.Count - 1; ii >= 0; ii--)
{
    Control cntrl = Controls[ii];
    Controls.remove(cntrl);
    cntrl.Dispose();
}

(从末尾开始,否则您将在迭代过程中更改每个控件的索引。)

哦,你不能在站在梯子上的时候移除它?感谢解释错误。当我尝试你的方法时,出现了一个错误,说没有Length的定义。我可能用错了方法。 - Altimus Prime
可能是.Count而不是.Length-我没有验证代码。 - zimdanen

0

你正在遍历从中删除的相同集合。使用此代码:

    List<Control> cleanControls = new List<Control>();
    foreach(Control ctr in Controls)
    {
       if(cntrl.GetType() != typeof(Button))
       {
          cleanControls.Add(ctr);
       }
       else
       {
         ctr.Dispose();
       }
    } 
    Controls = cleanControls;

就是这样!希望能帮到你!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接