0

以下代码片段可能看起来很奇怪,但它是重现与不同应用程序的复杂交互问题的一种非常简单的方法。

示例应用程序有两个表单,两个表单都注册 FormClosing 和 FormClosed 事件,只是在那里执行 Debug.WriteLine。

主要功能:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Form2 form2 = new Form2();
    form2.Show();
    Application.Run(new Form1());
}

当我关闭 Form2 时,我收到了预期的事件。当我关闭 Form1 时,应用程序退出并且 Form2 也被关闭。但是:Form2 的事件不会发生。

我覆盖了 Form2 的 WndProc。当我关闭 Form2 时,我收到

15.10.2012 10:25:04 WndProc - WM_CLOSE
15.10.2012 10:25:04 OnClosing
15.10.2012 10:25:04 Form2_FormClosing
15.10.2012 10:25:04 OnClosed
15.10.2012 10:25:04 Form2_FormClosed
...
15.10.2012 10:25:04 WndProc - WM_DESTROY
...
15.10.2012 10:25:04 WndProc - WM_NCDESTROY

当我关闭 Form1 时,Form2 没有收到 WM_CLOSE。但是收到了 WM_DESTROY 和 WM_NCDESTROY。

编辑:获得这种奇怪行为的另一种方法如下:该项目有三个表单,Form1 和 Form2 各有一个用于打开下一个表单的按钮。在form2的按钮点击事件中,执行:

Form3 frm3 = new Form3();
frm3.Parent = null;
frm3.Show(null);

同样,如上所述注册事件处理程序。关闭 form2 时,应用程序保持运行(仍显示 form1),但 form3 也关闭,并且没有收到 WM_CLOSE 事件。请注意,我已经将表单的 Parent 和 Owner 都设置为 null。

这种奇怪行为的原因是什么?

4

1 回答 1

3

WM_CLOSE发送消息以选择取消关闭。请参阅此流程图:

在此处输入图像描述

因此,当窗口即将被销毁时,此消息中没有必要。这是设计行为。当您关闭应用程序的主要形式时,Application.ThreadExit方法被调用。它描述为:

退出当前线程上的消息循环并关闭该线程上的所有窗口。

如果您希望所有打开的表单都接收WM_CLOSE消息,则需要Application.Exit改用:

通知所有消息泵它们必须终止,然后在处理完消息后关闭所有应用程序窗口。

因此只需订阅Form1_FormClosing事件并通知所有打开的窗口关闭:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    Application.Exit();
}
于 2012-10-15T08:51:56.637 回答