从 Invoke 中关闭表单

Closing Form from inside an Invoke

Invoke 中关闭表单,如下所示:

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

表单一关闭就抛出异常:

Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

但仅限于 NET 4.0。在 NET 4.5 上不抛出异常。

这是预期的行为吗?我该怎么办?

如果您在初始化期间启动一个线程,您不知道另一个线程中的初始化进行了多远。

您注意到不同 .Net 版本上的行为差异,但您无法确定不同机器上的顺序。

我已经使用自己的消息泵、队列和正常的计时器控件解决了 Windows 表单中的许多线程问题:

  • 在您的表单中添加一个计时器控件,间隔较小(250 毫秒)
  • 在表单中添加一个队列。
  • 让计时器事件使操作出队,然后执行它。
  • 在初始化或什至其他后台作业期间将操作添加到队列。

使用此方法会在初始化期间以及在 closing/disposing 表单期间出现后台作业问题,因为计时器只会在表单完全正常运行时触发。

这是因为 Close 方法关闭了窗体并销毁了它的句柄,然后在没有句柄的 Closed 窗体中调用了 MessageBox,所以出现了错误消息。

我不明白你的目的,但你应该将 Close 之后的代码移出 invoke,或者将 Close 移到它们之后。例如:

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

编辑:

关于 Control.Invoke 的 MSDN 注释:

The Invoke method searches up the control's parent chain until it finds a control or form that has a window handle if the current control's underlying window handle does not exist yet. If no appropriate handle can be found, the Invoke method will throw an exception. Exceptions that are raised during the call will be propagated back to the caller.