WPF Bug清单之(5)——隐藏模态对话框后变成非模态

发现这个问题时,隐约记得之前有人已经发过这个问题,想把链接放到这里,不过找了半天,实在找不到。日后如果找到了一定加上。

问题描述:用ShowDialog方法弹出一个模态对话框,然后将此对话框的Visibility属性设置为Hidden,再设置回Visible,发现这个对话框已经不是模态的了。

有人会觉得关就关了得了,也不会有这个问题,干什么要把Close取消掉然后再显示出来呢?因为这是有应用环境的。

应用环境:有些对话框,从逻辑上就是单例的,比如Office和Visual Studio里都有的查找对话框,显然没有必要同时显示两个。而且也没有必要每次重新实例化并显示出来,在用户关闭窗体时,将窗体隐藏起来会更好,这样上次查找的关键字还存在着。可以省去一些代码保存这个历史关键字。

当然,这种方式也会有不好的地方,欢迎大家指摘。

写了一个程序来模拟这个Bug,效果如下面三张图所示。

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

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

图3. 再点击主窗体的最后一个按钮,显示出来,已经是非模态对话框了

以前发Bug,一般没有去看过.NET的源代码,这次感觉这个Bug 有点儿太不应该了,就看了看源代码,发现WPF还特意为Dialog(模态的)的Hidden做了单独的处理,感觉就更不应该有问题了,我们来看看源代码。

DoDialogHide

[SecurityCritical, SecurityTreatAsSafe]
private void DoDialogHide()
{
   SecurityHelper.DemandUnmanagedCode();
   bool isActiveWindow = false;
   if (this._dispatcherFrame != null)
   {
     this._dispatcherFrame.Continue = false;
     this._dispatcherFrame = null;
   }
   if (!this._dialogResult.HasValue)
   {
     this._dialogResult = false;
   }
   this._showingAsDialog = false;    //Cause this Bug
   isActiveWindow = this._swh.IsActiveWindow;
   this.EnableThreadWindows(true);
   if ((isActiveWindow && (this._dialogPreviousActiveHandle != IntPtr.Zero)) && UnsafeNativeMethods.IsWindow(new HandleRef(this, this._dialogPreviousActiveHandle)))
   {
     UnsafeNativeMethods.SetActiveWindow(new HandleRef(this, this._dialogPreviousActiveHandle));
   }
}

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

从源代码上来看,WPF的Window似乎是使用下面的代码将一个窗体从非模态变成模态的。

SetAsModal

try
{
   //telluserswe'regoingmodal
   ComponentDispatcher.PushModal();
   _dispatcherFrame=newDispatcherFrame();
   Dispatcher.PushFrame(_dispatcherFrame);
}
finally
{
   //telluserswe'regoingnon-modal
   ComponentDispatcher.PopModal();
}

但是当我自己在使用里使用这个方法的时候,却发现根本达不到目的。后来突然想到一个方法,试了一下,就可以。解决方法是,不使用Visibility = Visible,使窗体再次显示出来。而且再调用一次ShowDialog方法来显示这个窗体。这个方法也许只有对WPF不熟悉或是非常熟悉的人才能想得出来(我是死马当作活马医碰对了),因为正常情况下,继续地第二次调用ShowDialog方法是会抛出异常的。类似的诡异的Window的异常在[WPF]如何在关闭非模态子窗体时用消息框确认——解决最小化窗体时抛出的异常里也有描述。

另外,在非UI线程弹出的MessageBox也是非模态的。这个解决方法很简单,只要在Dispatcher里弹出这个MessageBox就可以了。

本文配套源码

时间: 2025-01-20 12:12:17

WPF Bug清单之(5)——隐藏模态对话框后变成非模态的相关文章

WPF Bug清单之(4)——点击RadioButton的空白没有反应

在WPF BUG清单之二,介绍过RadioButton在绑定上的一个Bug.现在再来介绍它的另一个造成RadioButton的点击事件处理不正确的BUG.现象是:点在RadioButton的范围内,可这个RadioButton就是选不中. 先来看一个例子.Windows里一个常见的对话框,用了多个RadioButton.如下图所示. 图1.RadioButton使用范例 把RadioButton放在GroupBox的Header上,是很常见的一个用例,而且被微软的UX Guide所认可. 大家可

WPF Bug清单(序)与之(1)——可以多选的单选ListBox

从.NET 3.0发布至今,.NET Framework相继发布了.NET 3.5和.NET3.5 SP1.其间做了两个基于WPF的项目.发现现在的WPF的BUG真的是不算少.给程序的开发带来了不少的困扰--为了避开BUG,而不得不多写很多代码. 这个"WPF BUG清单"系列,将列出笔者在项目中遇到过的WPF的各种问题,也许不一定是BUG,但是会造成开发上的不便.更感觉WPF的第一次发布实在有赶鸭子上架的嫌疑.很多东西都还没有做就发布了.(跟Silverlight 1.0一样) 先举

WPF Bug清单之(12)

WPF Bug清单之(12)--与自定义Attached Property相关的Binding Path运行时错误 我们都知道DataBinding的格式是这样的: {Binding Path=PropertyName} 其中的Path=这几个字是可以省略的.从而简写成: {Binding PropertyName} 这个行为也在MSDN上面特别介绍过. 本文所指"解析错误"是指:当Property是自定义的AttachedProperty时, 第二种写法会产生运行时错误.如下代码所示

WPF Bug清单之(6)——Button的IsCancel属性失效

在上一篇中,描述了模态对话框隐藏之后变成了非模态的Bug,很多人回复表示这不算是一个Bug,我也表示理解.Bug只有在需求之下才有意义,不同的需求,对Bug的界定也不一样.作为一个Framework,.NET只能做到在多数时候是符合最广泛群体的需求的,就可以说它合格.但是对于前一篇描述的问题,想补充一下自己的考虑. Window的Show和ShowDialog,用于将窗体展现(我没有用显示)出来,而Close用于关闭.Close之后就不能再用Show或是ShowDialog再次将窗体展现出来,否

WPF Bug清单之(3)——暗中创建文件的打开文件对话框

这个Bug可以简单描述为:在使用OpenFileDialog尝试打开一个不存在的文件的时候,OpenFileDialog本身会创建这个不存在的文件并删除它,然后告诉用户这个文件不存在. 下面我们来写个程序来重现这个Bug.基本原理是使用FileSystemWatcher来监视文件夹. 创建使用了如图1所示的程序. 图1. 示例程序 首先选择一个文件夹,并监视里面的文件改变. 图2. 监视文件夹 然后在被监视的文件中尝试打开一个不存在的文件.这个打开文件对话框已经设置CheckFileExists

WPF Bug清单之(8)——RowDefinition中MaxHeight在一定条件下失效

再下一城. BUG描述:当RowDefinition的Height属性被设置为Auto时,MaxHeight将不会对这个Row的Height起到限制作用. Bug发现过程:想做一个像Visual Studio 2008里Error List一样的东西.平时自动占用最小的空间,可以在适当的时候自己弹出来,但是又不要弹得过高. 示例窗口代码如下: Demo Window <Window x:Class="InvaliMaxHeight.DemoWindow" xmlns="

WPF Bug清单之(2)——RadioButton的IsChecked绑定失效

.NET Framework已经算是一个很易用的库了.可以自动地为我们做很多事情,而且大都做得还不错.但是自动完成的事情很可能会有隐患,因为Framework本身是并不了解业务逻辑的.它自动完成的事情,可能会给我们帮倒忙. RadioButton就是其中一个. 先来从设置值的角度介绍一下WPF里的Dependency Property(以下简称DP).在WPF里控制一个控件的DP,有太多的方式.可以用Style,可以用Animation,可以用Data Binding,可以用Trigger,还有

WPF Bug清单之(13)——应该出现却没有出现的ListView水平滚动条

我们知道ListView在内容超出控件本身范围时,默认会把滚动条显示出来. 这个内容,显然应该包括Head和Items两个部分.无论哪个部分超出了,都应该 把水平滚动条显示出来. ListView的Bug就在于,当ListView中没有Item,且Headr的总长超过 ListView本身时,水平滚动条没有出现. 这个Bug很好重现.代码如下: <Grid x:Name="LayoutRoot"> <ListView Width="100">

WPF Bug清单之(11)——错位的RenderTransform动画

在WPF中制作位移类动画大致有3种方式,Margin.RenderTransform和 LayoutTransform.虽然3者的效果略有不同,但是不少情况下3种方式可以通用 .但是当你了解到RenderTransform所存在的Bug时,可能就需要考虑一番了. 我们都知道很多控件都有FocusVisualStyle,一般就是一个虚线框. RenderTransform的问题就在于, 控件的FocusVisualStyle中的元素,不会随着 控件本身一起被Transform. Bug的重现过程如