除非嵌套和重复,否则不要使用控件

时间:2013-02-20 06:39:57

标签: c# winforms loops foreach nested-loops

我在按钮单击事件处理程序中有一个foreach循环,我用它来摆脱所有坐在Y轴上同一点的控件。我有一个控件添加一行,然后我需要用户可以选择删除他们并不想添加的行。

当我单独使用foreach循环时,它总是错过两个项目 - 每次都是相同的两个项目。我确认Y值实际上是相同的。如果我继续运行该函数,它会在三次运行后删除该行上的所有控件。但是,如果我使用所有相同的值嵌套foreach循环,它就可以工作。请参阅下面的代码。

这似乎是一种非常草率的方式,但它也是唯一对我有用的解决方案。我看到其他一些帖子说要在循环中声明第二个变量(即Control z = c; if(z.Location....))。这并没有对这里的行为产生任何影响。任何人都可以解释为什么foreach循环本身并不起作用?如何在没有重复嵌套的情况下修复它?

工作:

    internal void MinButt_Click(object sender, EventArgs e)
    {
        Scratch.tScratch.panel2.Controls.RemoveByKey("Record" + arrDynamY[0].ToString());
        foreach (Control c in Scratch.tScratch.panel2.Controls)
        {
            if (c.Location.Y == arrDynamY[1])
            {
                c.Dispose();
            }

            foreach (Control ctrl in Scratch.tScratch.panel2.Controls)
            {
                if (ctrl.Location.Y == arrDynamY[1])
                {
                    ctrl.Dispose();
                }
            }
        }
    }

每次错过相同的两个控件:

    internal void MinButt_Click(object sender, EventArgs e)
    {
        Scratch.tScratch.panel2.Controls.RemoveByKey("Record" + arrDynamY[0].ToString());
        foreach (Control c in Scratch.tScratch.panel2.Controls)
        {
            if (c.Location.Y == arrDynamY[1])
            {
                c.Dispose();
            }
        }
    }

4 个答案:

答案 0 :(得分:3)

您应首先获取用于删除和删除它们的控件,如下所示:

var controlsToRemove = from Control c in Scratch.tScratch.panel2.Controls
                       where c.Location.Y == arrDynamY[1]
                       select c;

foreach (var c in controlsToRemove.ToArray())
{
    Scratch.tScratch.panel2.Controls.Remove(c);
    c.Dispose();
}

答案 1 :(得分:1)

您正在修改(在这种情况下处理)您正在迭代的集合的项目,我相信这是导致意外行为的原因,您可以使用for循环来避免此问题:< / p>

        for (int i = Scratch.tScratch.panel2.Controls.Length - 1; i >= 0; i-- )
            if (Scratch.tScratch.panel2.Controls[i].Location.Y == arrDynamY[1])
                Scratch.tScratch.panel2.Controls[i].Dispose();

我假设Scratch.tScratch.panel2.Controls可以作为数组访问。

答案 2 :(得分:0)

也许在单独的循环中执行dispose,它可能会影响其他控件

试试这个

internal void MinButt_Click(object sender, EventArgs e)
{
    Scratch.tScratch.panel2.Controls.RemoveByKey("Record" + arrDynamY[0].ToString());
    var controlsToDispose = new List<Control>();
    foreach (Control c in Scratch.tScratch.panel2.Controls)
    {
        if (c.Location.Y == arrDynamY[1])
        {
            controlsToDispose.Add(c);
        }
    }
    foreach (Control c in controlsToDispose )
    {
        c.Dispose();
    }              
}

答案 3 :(得分:-1)

这是因为当您在控件上调用Dispose()时,它只会停留在内存中,直到GC启动。请尝试以下操作。

List<Control> controlsToDispose = new List<Control>();
foreach (Control c in Scratch.tScratch.panel2.Controls)
{
       if (c.Location.Y == arrDynamY[1])
       {
           controlsToDispose.Add(c);
           c.Dispose();
       }
}
while(controlsToDispose.Count>0)
{
      Control ctrl = controlsToDispose[0];
      controlsToDispose.RemoveAt(0);
      ctrl.Dispose();
}