2012-10-15 64 views
0

下面的代碼片段可能看起來很奇怪,但它是一個非常簡單的方法來重現與其他應用程序的複雜交互問題。消失FormClosing/FormClosed事件

示例應用程序有兩種形式,兩種形式都註冊FormClosing和FormClosed事件,只是在那裏做一個Debug.WriteLine。

的主要功能作用:

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

當我關閉窗體2,我收到了事件的預期。當我關閉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。

這種奇怪行爲的原因是什麼?

回答

3

WM_CLOSE消息被髮送以具有取消關閉的選項。看到這個流程圖:

enter image description here

因此,有在此消息沒有必要,當窗口即將被銷燬反正。這是設計行爲。當您關閉主應用程序時,將調用Application.ThreadExit方法。它描述爲:

退出當前線程上的消息循環並關閉線程上的所有窗口 。

如果你想所有打開的形式接收WM_CLOSE消息,您需要使用Application.Exit代替:

通知所有消息泵必須終止,然後關閉 所有應用程序窗口後的消息具有已被處理。

因此只需訂閱Form1_FormClosing事件,並告知關閉所有打開的窗口:

private void Form1_FormClosing(object sender, FormClosingEventArgs e) 
{ 
    Application.Exit(); 
} 
+0

感謝這個偉大的解釋。現在我明白了爲什麼在這個例子中沒有得到消息。 –

+0

但我們首先發現問題的環境要複雜得多。 ThirdParty定義了一個C++接口。我們在混合模式(非託管/託管)dll中實現它。當ThirdParty調用StartUp方法時,我們創建一個通信窗口(並將桌面設置爲其所有者)。 當ThirdParty關閉我們的系統加載窗口時,我們的窗口也消失 - 沒有事件。但是我們的系統保持加載狀態(即它們不卸載應用程序域)。現在我們必須找出哪些其他方式來關閉窗口而不會收到事件。 –

+0

你可以在你的Form2上重載'WndProc',並通過調用'Close()'方法來處理'WM_DESTROY'消息。它將處理形式和資源。 –