[WPF Bug清单]之(5)——隐藏模态对话框后变成非模态
发现这个问题时,隐约记得之前有人已经发过这个问题,想把链接放到这里,不过找了半天,实在找不到。日后如果找到了一定加上。
问题描述:用ShowDialog方法弹出一个模态对话框,然后将此对话框的Visibility属性设置为Hidden,再设置回Visible,发现这个对话框已经不是模态的了。
有人会觉得关就关了得了,也不会有这个问题,干什么要把Close取消掉然后再显示出来呢?因为这是有应用环境的。
应用环境:有些对话框,从逻辑上就是单例的,比如Office和Visual Studio里都有的查找对话框,显然没有必要同时显示两个。而且也没有必要每次重新实例化并显示出来,在用户关闭窗体时,将窗体隐藏起来会更好,这样上次查找的关键字还存在着。可以省去一些代码保存这个历史关键字。
当然,这种方式也会有不好的地方,欢迎大家指摘。
写了一个程序来模拟这个Bug,效果如下面三张图所示。

图1. 主窗体,点第一个按钮

图2. 弹出的模态对话框,点击按钮将自己隐藏

图3. 再点击主窗体的最后一个按钮,显示出来,已经是非模态对话框了
以前发Bug,一般没有去看过.NET的源代码,这次感觉这个Bug 有点儿太不应该了,就看了看源代码,发现WPF还特意为Dialog(模态的)的Hidden做了单独的处理,感觉就更不应该有问题了,我们来看看源代码。

其中直接把_showingAsDialog设置为了false,当再次把窗体的Visibility设置为Visible的时候,Window类又会根据这个变量的值来判断是否将窗体按模态的方式显示出来。而MS对这行代码的的注释仅仅是“// clears _showingAsDialog”。
从源代码上来看,WPF的Window似乎是使用下面的代码将一个窗体从非模态变成模态的。

但是当我自己在使用里使用这个方法的时候,却发现根本达不到目的。后来突然想到一个方法,试了一下,就可以。解决方法是,不使用Visibility = Visible,使窗体再次显示出来。而且再调用一次ShowDialog方法来显示这个窗体。这个方法也许只有对WPF不熟悉或是非常熟悉的人才能想得出来(我是死马当作活马医碰对了),因为正常情况下,继续地第二次调用ShowDialog方法是会抛出异常的。类似的诡异的Window的异常在[WPF]如何在关闭非模态子窗体时用消息框确认——解决最小化窗体时抛出的异常里也有描述。
另外,在非UI线程弹出的MessageBox也是非模态的。这个解决方法很简单,只要在Dispatcher里弹出这个MessageBox就可以了。
同系列的其它文章:
[WPF Bug清单](序)与之(1)——可以多选的单选ListBox
[WPF Bug清单]之(2)——RadioButton的IsChecked绑定失效
[WPF Bug清单]之(3)——暗中创建文件的打开文件对话框
[WPF Bug清单]之(4)——点击RadioButton的空白没有反应
[WPF Bug清单]之(6)——Button的IsCancel属性失效
[WPF Bug清单]之(7)——顽固的Error Template
[WPF Bug清单]之(8)——RowDefinition中MaxHeight在一定条件下失效
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述