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

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

 

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

 

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

 

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

 

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

 

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

 

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

 

 

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

 

 

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

 

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

 

ContractedBlock.gif ExpandedBlockStart.gif DoDialogHide
[SecurityCritical, SecurityTreatAsSafe]
private void DoDialogHide()
ExpandedBlockStart.gifContractedBlock.gif
{
    SecurityHelper.DemandUnmanagedCode();
    
bool isActiveWindow = false;
    
if (this._dispatcherFrame != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
this._dispatcherFrame.Continue = false;
        
this._dispatcherFrame = null;
    }

    
if (!this._dialogResult.HasValue)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
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(thisthis._dialogPreviousActiveHandle)))
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        UnsafeNativeMethods.SetActiveWindow(
new HandleRef(thisthis._dialogPreviousActiveHandle));
    }

}

 

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

 

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

 

ContractedBlock.gif ExpandedBlockStart.gif SetAsModal
try
{
    
// tell users we're going modal
    ComponentDispatcher.PushModal(); 

    _dispatcherFrame 
= new DispatcherFrame(); 
    Dispatcher.PushFrame(_dispatcherFrame); 
}
finally 
{
    
// tell users we're going non-modal
    ComponentDispatcher.PopModal();
}

 

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

 

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

更多关于WPF Bug 

同系列的其它文章:

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

[WPF Bug清单](2)——RadioButtonIsChecked绑定失效

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

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

[WPF Bug清单](6)——ButtonIsCancel属性失效

[WPF Bug清单](7)——顽固的Error Template

[WPF Bug清单](8)——RowDefinitionMaxHeight在一定条件下失效

[WPF Bug清单](9)——消失的光标

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值