问题 WPF和棱镜视图叠加


我需要一些帮助,使用棱镜框架覆盖视图。它比这更复杂,所以让我解释一下。我也可能过度思考这个:D

我有shell(wpf窗口),我在模块中有2个视图(A和B - 两个用户控件)。 当shell加载时,它加载视图A.在视图A上,我有一个“弹出”视图B的按钮 对于一些用户输入。所以我自然会想到某种模态窗口/控件,甚至可能是一个弹出窗口。然而我面对弹出窗口的问题是,当我移动shell时,弹出窗口仍然是固定的,它不会阻止视图A中的事件。我已经尝试禁用视图A来停止被触发的事件,我也尝试使用一个来获取视图B随shell移动。只有画布可以工作,但我现在需要一种方法来阻止它'。无论如何,我可以用棱镜将视图覆盖在另一个视图的顶部吗?或者其他人如何用prism和wpf创建模态弹出窗口?任何建议或指示将不胜感激。


3068
2018-03-19 13:09


起源



答案:


如果你想使用 嵌入式 没有额外窗口的对话框,您可以使用Prism的RegionManager来实现概述的行为。诀窍是将PopUp区域与可视树中的主区域平行:

<Grid>
   <ContentControl cal:RegionManager.RegionName="MainRegion" IsEnabled={Binding IsNoPopUpActive} />
   <ContentControl cal:RegionManager.RegionName="PopUpRegion"/>
</Grid>

现在使用RegionManager将视图“A”放入“MainRegion”。创建一个类似于IPopUpDialogController的控制器类。它应该负责根据需要将您的视图“B”(或您的应用程序中的任何其他PopUpView)放入“PopUpRegion”。另外,它应该控制一个标志,指示启用或禁用基础“MainRegion”。这样,在弹出窗口关闭之前,用户将无法使用视图“A”中的控件进行播放。

在将帧推送到Dispatcher之前,通过使用ComponentDispatcher.PushModal(),甚至可以以模态方式完成此操作。但是,我建议避免使用模态对话框。


更新:根据注释中的要求,可以在支持视图模型中实现IsNoPopUpActive。在那里你可以将它链接到RegionManager的弹出区域的View集合:

public bool IsNoPopUpActive 
{ 
    get { return _regionManager.Regions["PopUpRegion"].Views.Count() == 0; }
}

请记住,一旦修改了视图集合(添加/删除弹出窗口),就会触发PropertyChanged事件。

仅供参考:现在我避免在后台禁用控件,而是插入透明面板。这可以避免单击背景控件。但是,这不能处理键盘输入(选项卡到控件)。要修复键盘输入,您需要确保键盘焦点 被困 在弹出窗口中(关于WPF Focus概念的MSDN)。

将以下焦点属性添加到弹出区域应该可以解决问题:

KeyboardNavigation.DirectionalNavigation="None"
KeyboardNavigation.ControlTabNavigation="None"
KeyboardNavigation.TabNavigation="Cycle"
KeyboardNavigation.TabIndex="-1"

14
2018-03-19 15:29



非常感谢!我实际上做了另一种方式,但非常类似于你。我所做的是使用内容控件为我的shell区域,并在模块A中创建一个项目控制区域。我设置布局使用项目控制区域中的网格,所有我做了区域“弹出”内的激活和非活动视图。我试着试试你的解决方案。将对结果进行反馈。再次感谢! - Zaheer
嗨,奥利,你能给出如何包含“IsNoPopUpActive”属性的片段吗? - ioWint
嗨ioWint,我已经更新了答案。 - olli-MSFT


答案:


如果你想使用 嵌入式 没有额外窗口的对话框,您可以使用Prism的RegionManager来实现概述的行为。诀窍是将PopUp区域与可视树中的主区域平行:

<Grid>
   <ContentControl cal:RegionManager.RegionName="MainRegion" IsEnabled={Binding IsNoPopUpActive} />
   <ContentControl cal:RegionManager.RegionName="PopUpRegion"/>
</Grid>

现在使用RegionManager将视图“A”放入“MainRegion”。创建一个类似于IPopUpDialogController的控制器类。它应该负责根据需要将您的视图“B”(或您的应用程序中的任何其他PopUpView)放入“PopUpRegion”。另外,它应该控制一个标志,指示启用或禁用基础“MainRegion”。这样,在弹出窗口关闭之前,用户将无法使用视图“A”中的控件进行播放。

在将帧推送到Dispatcher之前,通过使用ComponentDispatcher.PushModal(),甚至可以以模态方式完成此操作。但是,我建议避免使用模态对话框。


更新:根据注释中的要求,可以在支持视图模型中实现IsNoPopUpActive。在那里你可以将它链接到RegionManager的弹出区域的View集合:

public bool IsNoPopUpActive 
{ 
    get { return _regionManager.Regions["PopUpRegion"].Views.Count() == 0; }
}

请记住,一旦修改了视图集合(添加/删除弹出窗口),就会触发PropertyChanged事件。

仅供参考:现在我避免在后台禁用控件,而是插入透明面板。这可以避免单击背景控件。但是,这不能处理键盘输入(选项卡到控件)。要修复键盘输入,您需要确保键盘焦点 被困 在弹出窗口中(关于WPF Focus概念的MSDN)。

将以下焦点属性添加到弹出区域应该可以解决问题:

KeyboardNavigation.DirectionalNavigation="None"
KeyboardNavigation.ControlTabNavigation="None"
KeyboardNavigation.TabNavigation="Cycle"
KeyboardNavigation.TabIndex="-1"

14
2018-03-19 15:29



非常感谢!我实际上做了另一种方式,但非常类似于你。我所做的是使用内容控件为我的shell区域,并在模块A中创建一个项目控制区域。我设置布局使用项目控制区域中的网格,所有我做了区域“弹出”内的激活和非活动视图。我试着试试你的解决方案。将对结果进行反馈。再次感谢! - Zaheer
嗨,奥利,你能给出如何包含“IsNoPopUpActive”属性的片段吗? - ioWint
嗨ioWint,我已经更新了答案。 - olli-MSFT


如果您使用带Prism的WPF + MVVM,您可以查看此消息视图覆盖控制器。关于这种方法的好处是你可以使用模拟覆盖控制器在视图模型上编写单元测试,并让模拟控制器返回用户在叠加层中选择的结果。

你可以在这里找到它: http://presentationlayer.wordpress.com/2011/05/24/wpf-overlay-message-view-controller/

希望这可以帮助


2
2018-05-26 17:08