關閉模態窗口後,父窗口竟然跑到了其餘窗口的後面

 

顯示一個模態窗口,正常而廣泛的操做。然而卻一直有一個難纏的 BUG:當關閉模態窗口時,父窗口有時會跑到其餘程序窗口的後面!spa

而最近讀到了微軟工程師寫過的話以後,明白了這個 BUG 的產生原因以及解決方法。3d


這是什麼 BUG?

彈出模態窗口

  1. 彈出一個模態窗口,而後將模態窗口的父窗口設置爲自身窗口;
  2. 切換到其餘程序窗口中(好比 Windows 資源管理器窗口);
  3. 切換回此模態窗口,而後關閉這個模態窗口上。

你會發現,模態窗口關閉後,父窗口並無回到當前的頂層顯示中。取而代之的,是其餘程序的窗口(好比 Windows 資源管理器窗口)。
用一張圖來描述這個 BUG,將是這樣的:code

有這兩個窗口,其中右邊那個是咱們開發的:blog

兩個窗口

咱們的窗口在資源管理器上面。而後,咱們彈出模態子窗口:事件

咱們在上面

如今,咱們操做一下資源管理器:資源

操做資源管理器

而後,回到模態子窗口中,把它關掉:開發

關掉模態子窗口

咱們期待模態子窗口關掉後,它的父窗口會在頂層繼續供咱們操做,但實際上,Windows 資源管理器卻成爲了頂層,咱們的程序「掉下去了」:產品

不符合預期的結果

解釋和解決方法

在《Windows 進化啓示錄》書中,微軟有說到:it

當銷燬模態對話框時,這個對話框恰好是擁有前臺焦點的窗口。如今,窗口管理器須要找到其餘的窗口並把前臺焦點交給這個窗口。
窗口管理器會首先試着把前臺焦點交給對話框的全部者窗口,但此時這個窗口卻仍然是禁止的,所以窗口管理器將跳過全部者窗口,並繼續查找沒有被禁止的窗口。class

這很明顯是 Windows 的 BUG,然而讓微軟感到無奈的是,常常有程序喜歡依賴於微軟的 BUG 進行開發,一旦微軟修復了 BUG,那些依賴於 BUG 開發的程序將變得不正常!

爲解決兼容性問題的微軟工程師默哀一分鐘……

我曾經嘗試在模態子窗口關閉後激活一下父窗口,但這樣會致使窗口的層級閃爍一下(Windows 資源管理器會短暫地顯示到咱們的窗口之上)。

而這本書做者推薦的方法是:

  1. 從新激活全部者窗口
  2. 銷燬模態對話框

因而,我試着監聽模態子窗口的 Closing 事件,在其中寫下主窗口的激活調用,自此 BUG 纔算解決。

public ChildModalWindow()
{
    Closing += (sender, e) => Owner?.Activate();
}

將這樣的解決辦法封裝成附加屬性給全部的模態子窗口,這樣設置附加屬性便可解決問題。或者統一模態子窗口的窗口樣式,在樣式中解決這個 BUG,這樣,全部使用了此窗口樣式的模態子窗口也將解決問題。


參考資料

  • 《偉大的產品 —— Windows 進化啓示錄》by 微軟軟件工程師 Raymond Chen
相關文章
相關標籤/搜索