C# 关闭或隐藏表单会导致跨线程错误

C# 关闭或隐藏表单会导致跨线程错误,c#,.net,winforms,C#,.net,Winforms,这个简单的任务让我一次又一次地感到困惑 我有一系列的子表单。数组是在另一个窗体的构造函数中启动的: frmChildren = new ChildGUI[20]; 当用户请求查看子表单时,我执行以下操作: if (frmChildren[nb] == null) { frmChildren[nb] = new ChildGUI(); frmChildren[nb].MdiParent = this.MdiParent; } frmChildren[nb].Show(); 到目

这个简单的任务让我一次又一次地感到困惑

我有一系列的子表单。数组是在另一个窗体的构造函数中启动的:

frmChildren = new ChildGUI[20];
当用户请求查看子表单时,我执行以下操作:

if (frmChildren[nb] == null)
{
    frmChildren[nb] = new ChildGUI();
    frmChildren[nb].MdiParent = this.MdiParent;
}
frmChildren[nb].Show();
到目前为止,此有效。在后台,我可以下载这些表单的新内容。下载完成后,我触发一个ChildChange事件。这就是它停止工作的地方。 我只想关闭/隐藏任何打开的表单,然后重新生成一组新的-frmChildren=new ChildGUI[20];-以下是众多试验之一:

        for (int i = 0; i < frmChildren.Length;i++ )
        {
            if (frmChildren[i] != null)
            {
                //frmChildren[i].BeginInvoke(new EventHandler(delegate
                //{
                    frmChildren[i].Close();
                //}));
            }
        }             
        frmChildren= new ChildGUI[20];
for(int i=0;i

我在.Close()上得到一个跨线程异常。注意,我已经尝试过调用,但这样做会绕过=由于某种原因无效。我认为这可能与垃圾收集器有关。有人有输入吗?

问题是您的匿名方法正在捕获
i
——因此,当它在UI线程中实际调用时,您已经获得了不同的
i
值,该值可能为空。试试这个:

for (int i = 0; i < frmChildren.Length; i++)
{
    ChildGUI control = frmChildren[i];
    if (control != null)
    {
        control.BeginInvoke(new EventHandler(delegate
        {
            control.Close();
        }));
    }
}             
frmChildren = new ChildGUI[20];
顺便说一句,您可以使用这样一个事实:您只想调用一个void方法,从而使代码稍微简单一些。由于不再使用匿名方法,您可以取消“内部”变量:

foreach (ChildGUI control in frmChildren)
{
    if (control != null)
    {
        control.BeginInvoke(new MethodInvoker(control.Close));
    }
}             
frmChildren = new ChildGUI[20];

我已经用foreach尝试了上述相同的代码。foreach会有什么不同?奇怪的是,你的解决方案奏效了+1感谢您提供的链接,该链接解释了为什么会这样。如果您不关心异步关闭表单,我认为您可以将BeginInvoke替换为Invoke,而不是引入另一个变量。因为Invoke是同步的,所以迭代变量
i
的值还没有改变。@Lily:对于foreach循环,您仍然需要在循环中引入一个额外的变量。这是最重要的一点。
foreach (ChildGUI control in frmChildren)
{
    if (control != null)
    {
        control.BeginInvoke(new MethodInvoker(control.Close));
    }
}             
frmChildren = new ChildGUI[20];