顯示一個模態窗口,正常而廣泛的操做。然而卻一直有一個難纏的 BUG:當關閉模態窗口時,父窗口有時會跑到其餘程序窗口的後面!spa
而最近讀到了微軟工程師寫過的話以後,明白了這個 BUG 的產生原因以及解決方法。3d
你會發現,模態窗口關閉後,父窗口並無回到當前的頂層顯示中。取而代之的,是其餘程序的窗口(好比 Windows 資源管理器窗口)。
用一張圖來描述這個 BUG,將是這樣的:code
有這兩個窗口,其中右邊那個是咱們開發的:blog
咱們的窗口在資源管理器上面。而後,咱們彈出模態子窗口:事件
如今,咱們操做一下資源管理器:資源
而後,回到模態子窗口中,把它關掉:開發
咱們期待模態子窗口關掉後,它的父窗口會在頂層繼續供咱們操做,但實際上,Windows 資源管理器卻成爲了頂層,咱們的程序「掉下去了」:產品
在《Windows 進化啓示錄》書中,微軟有說到:it
當銷燬模態對話框時,這個對話框恰好是擁有前臺焦點的窗口。如今,窗口管理器須要找到其餘的窗口並把前臺焦點交給這個窗口。
窗口管理器會首先試着把前臺焦點交給對話框的全部者窗口,但此時這個窗口卻仍然是禁止的,所以窗口管理器將跳過全部者窗口,並繼續查找沒有被禁止的窗口。class
這很明顯是 Windows 的 BUG,然而讓微軟感到無奈的是,常常有程序喜歡依賴於微軟的 BUG 進行開發,一旦微軟修復了 BUG,那些依賴於 BUG 開發的程序將變得不正常!
爲解決兼容性問題的微軟工程師默哀一分鐘……
我曾經嘗試在模態子窗口關閉後激活一下父窗口,但這樣會致使窗口的層級閃爍一下(Windows 資源管理器會短暫地顯示到咱們的窗口之上)。
而這本書做者推薦的方法是:
- 從新激活全部者窗口
- 銷燬模態對話框
因而,我試着監聽模態子窗口的 Closing
事件,在其中寫下主窗口的激活調用,自此 BUG 纔算解決。
public ChildModalWindow()
{
Closing += (sender, e) => Owner?.Activate();
}
將這樣的解決辦法封裝成附加屬性給全部的模態子窗口,這樣設置附加屬性便可解決問題。或者統一模態子窗口的窗口樣式,在樣式中解決這個 BUG,這樣,全部使用了此窗口樣式的模態子窗口也將解決問題。