今天在百度知道看到这个一个问题:
【问题:】
点击button1之后只有两个按钮消失,再点击剩下两个才能消失。按我写的这个语句来说应该是一下子全部消失才对啊。求告诉哪出错了!十分只是初步悬赏,如果解决了了会有追加!!下面是button1点击事件的处理代码。。。
private void button1_Click(object sender, EventArgs e) { foreach (Control c in this.panel1.Controls)
这是click事件的处理办法
private void button1_Click(object sender, EventArgs e)
{
foreach (Control c in this.panel1.Controls)
{
c.Dispose();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/7b52d7f9adc79e0b00a4846efc5bb039.jpeg)
【有网友有如下解答:】
我试了一下,是foreach遍历的问题
似乎Control在Dispose的时候会把自己从父控件的Controls集合中移出。那么,根据迭代器的设计规范,在迭代过程中集合不应该被改变,如果迭代器检查到集合被改变了应该抛出异常,但是这里没有抛出异常。【注1】
结果就是异常迭代——foreach没有遍历集合中所有内容。你在c.Dispose()前面或后面加个MessageBox就可以看出来了,foreach只执行了两次。
改成用for循环+索引方式访问元素就可以了:
for(int i=panel1.Controls.Count -1;i>=0;i--)
{
Control c=panel1.Controls[i];
c.Dispose();
}
或者直接清空Controls集合,等垃圾回收执行析构函数:
panel1.Controls.Clear();
【注1】
看了下ControlCollection的MoveNext源码,果然没有检查集合的改变:
public bool MoveNext()
{
if ((this.current < (this.controls.Count - 1)) && (this.current < (this.originalCount - 1)))
{
this.current++;
return true;
}
return false;
}
当你迭代完第二个元素后,this.controls.Count等于3-2=1,this.current=1,迭代就停止了。实际上集合中还有两个元素。
【替代解决方案】
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Queue<Control> query = new Queue<Control>();//临时存储获取到的control控件
/// <summary>
/// 递归获取panel1上的所有控件,并临时存储到一个队列中
/// </summary>
/// <param name="item"></param>
void DS(Control item)
{
for (int i = 0; i < item.Controls.Count;i++ )
{
if (item.Controls[i].HasChildren)
{
DS(item.Controls[i]);
}
else
{
query.Enqueue(item.Controls[i]);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
DS(panel1);
//删除遍历到的控件
while (query.Count != 0)
{
query.Dequeue().Dispose();
}
}
}
}