显示一个模态窗口,正常而广泛的操做。然而却一直有一个难缠的 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,这样,全部使用了此窗口样式的模态子窗口也将解决问题。