从Invoke内部关闭表单

时间:2015-04-28 10:32:24

标签: c# winforms exception invoke ui-thread

Invoke内部关闭表单,如下所示:

Invoke(new Action(() => {
    Close();
    MessageBox.Show("closed in invoke from another thread");
    new Form1();
}));
表单关闭后,

会抛出异常:

  

在窗口之前无法在控件上调用Invoke或BeginInvoke   句柄已经创建。

但仅限于.NET 4.0。在.NET 4.5上没有抛出任何异常。

这是预期的行为吗?我应该怎么做呢?

2 个答案:

答案 0 :(得分:2)

如果你在初始化期间启动一个线程,你不知道初始化在另一个线程中已经走了多远。

您注意到不同.Net版本的行为存在差异,但您无法确定不同计算机上的事物顺序。

我使用自己的消息泵解决了Windows窗体中的许多线程问题,使用了队列和普通的Timer控件:

  • 向窗体添加一个计时器控件,间隔时间间隔很小(250毫秒)
  • 在表单中添加队列。
  • 让计时器事件使操作出列,并执行它。
  • 在初始化期间向队列添加操作,甚至是其他后台作业。

使用此方法会在初始化期间出现后台作业问题,但也会在关闭/处理表单时出现问题,因为只有在表单完全正常运行时才会触发计时器。

答案 1 :(得分:2)

那是因为Close方法关闭了表单并销毁它的句柄,然后在没有句柄的Closed表单中调用MessageBox,因此显示错误消息。

我不了解你的目的,但你应该在关闭调用后移动代码,或者在它们之后移动关闭。例如:

Invoke(new Action(() => {
    Hide();
    MessageBox.Show("closed in invoke from another thread");
    new Form1();
    Close();
}));

修改

MSDN关于Control.Invoke的说明:

  

如果当前控件的基础窗口句柄尚不存在,则Invoke方法搜索控件的父链,直到找到具有窗口句柄的控件或窗体。如果找不到合适的句柄,Invoke方法将抛出异常。呼叫期间引发的异常将传播回呼叫者。