使用Prism和MVVM模式在WPF中制作模态对话框的“优美”方法

18
昨天我使用谷歌搜索了一些关于如何在WPF中使用PRISM 4.1和MVVM模式创建可重用的漂亮对话框的方法。我找到了一些示例,但必须说没有一个像我想要的那样"漂亮"。
这个:WPF Modal Dialog (没有MVVM-> 不用)
这个很不错:Showing Dialogs when using the MVVM Pattern(但它仍然使用自制的ServiceLocator,而我不需要,因为我正在使用IUnity容器。我可以使用逻辑并将其重写到Unity,但在我诚实的意见中,这不是“漂亮”的方式。
好吧,在网上搜索了一段时间后,某个博客(现在找不到来源了)告诉我PRISM Framework有一个叫做“interaction requests”的东西。所以我查看了prism文档,并在“高级mvvm场景”主题下找到了一小部分内容,但文档中提供的信息不足。

我想知道是否有任何关于如何在prism wpf中使用mvvm实现一个很棒的模态对话框的好例子或博客文章。

编辑: 关于评论中的问题:

什么使一个模态对话框很棒?

确实是一个好问题。

  1. 它必须是模态的(当对话框打开时,其余UI应该被冻结)
  2. 对话框视图可以有自己的视图模型,或者至少我想给对话框视图提供一个对象实例,并返回一个对象到父视图
  3. 视图应该是自己的“xaml”文件
  4. 来自.NET的dialogresult功能,或者至少一种获取用户在对话框中单击了什么响应的方法

2
嗯...什么让模态对话框变得很棒呢?如果您能提供比这更多的技术要求,那就太好了,就像这个“棒极了”的请求一样。 ;) - DHN
1
你在编辑中发布的特性列表不是已经在基本的WPF中(没有PRISM参与)吗? - noseratio - open to work
1
Window.ShowDialog()不会冻结用户界面。相反,它通过禁用父窗口来阻止用户输入,然后启动一个嵌套的模态消息循环(新的Dispatcher帧)。所有这些都在同一个UI线程上发生。因此,它的行为与WinForms Form.ShowDialog()类似。 - noseratio - open to work
是的,用户应该能够在后台看到父窗口,但在对话框打开时不能执行任何操作。 - darkdog
1
@darkdog,冻结UI和禁用UI是两个不同的操作。调用 Thread.Sleep(10000) 会冻结整个UI。调用 Window.ShowDialog() 会禁止用户输入进入父窗口,但不会冻结它。您甚至可以从模态对话框更新父窗口的UI。打开Visual Studio并在菜单中选择“帮助”->“关于”,这是您要寻找的那种对话框吗? - noseratio - open to work
显示剩余8条评论
4个回答

20

PRISM 5.0推出了使用PopupWindowAction快速展示模态对话框的解决方案。

<prism:InteractionRequestTrigger SourceObject="{Binding CustomPopupViewRequest, Mode=OneWay}">
    <prism:PopupWindowAction>
        <prism:PopupWindowAction.WindowContent>
            <views:CustomPopupView />
        </prism:PopupWindowAction.WindowContent>
    </prism:PopupWindowAction>
</prism:InteractionRequestTrigger>

1
这让我朝着正确的方向前进,但需要更多的上下文来使其更加完善:使用 Prism Library 5.0 for WPF 的交互性快速入门 - Paul

5

交互请求需要更多的前期工作,但从MVVM纯主义者的角度来看,这绝对是正确的方法...

我在Karl Shifflett的MVVM In The Box培训扩展中看到了一个示例,介绍了如何使用Prism实现此目标。

据我记得,这个示例还有很多不足之处,但它应该能为您指明正确的方向。

这种在视图中的“对话框”的问题在于它不允许对话框超出父窗口的边界。好的一面是,您可以做很多花哨的布局和动画效果。


这个 VS2010 模板需要安装 2010 版本才能使用 :( - darkdog
1
你所需要的只是源文件,不必安装它。博客上有一个SkyDrive链接,其中第二个Zip文件包含代码。交互请求内容位于MVVMTraining\Acme Common\Acme.Prism\InteractionRequest下。 - Mark
那就是我一直在寻找的! - darkdog
不过需要提醒的是,那段代码相当笨重,特别是在禁用网格上的其他控件方面。可能有更好的示例可以在其他地方找到。我使用视图中的特殊InteractionContentControl来完成它,而不是使用网格。 - Mark

2

请查看我在这里发布的文章。

这是关于IT技术的内容,涉及MVVM模式。如果您想要在ViewModel中实现一个服务,只需简单地:

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);

为了公平起见,我最近添加了一些重载以获得更多的功能,例如:bool? ShowDialog(string titel, object datacontext, double minHeigth = 0, double minWidth=0, double maxHeigth = double.PositiveInfinity, double maxWidth = double.PositiveInfinity); 或 bool? ShowDialog(string titel, object datacontext, ApplicationSettingsBase settings, string pathHeigthSetting, string pathWidthSetting, double minHeigth = 0, double minWidth = 0, double maxHeigth = double.PositiveInfinity, double maxWidth = double.PositiveInfinity); - blindmeis
对话框服务方法很差,因为... a) 没有办法选择对话框的父窗口,b) 显示通知应该由视图决定。使用对话框服务,您完全排除了视图的参与。 - Mark
1
在我的MVVM应用程序中,VIEWMODEL决定何时打开模态对话框,而modaldialogviewmodel的DATATEMPLATE则决定了模态对话框的外观。modaldialog的父级仅为应用程序的mainwindow。因此,我认为这不是一种糟糕的方法,而是一种简单的方法 :) - blindmeis
如果你有两个顶级窗口会怎么样? - Mark
我没有遇到过这种情况,但是当您在第二个顶级窗口上打开模态对话框时,应该发生什么 - 您不想或者您希望访问第一个顶级窗口,而您的模态对话框仍然打开着? - blindmeis
@blindmeis,你可以随时利用PRISM的交互请求将你的对话框绑定到特定的窗口。https://msdn.microsoft.com/zh-cn/library/gg405494(v=pandp.40).aspx#sec12 - Denis Brat

1
注意:我没有使用PRISM,我的回答假设仅使用WPF和MVVM。我认为这不是一个主要问题,因为你的要求清单可以在没有PRISM的情况下满足(PRISM可以随后添加到基本解决方案中)。
我在Github上有一个项目,提供了一个称为ModalContentPresenter的自定义FrameworkElement,允许显示模态内容。该元素基本上由两个窗格组成,一个层叠在另一个上面。后面的窗格承载主要内容,前面的窗格承载模态内容。该元素具有一个依赖属性,用于控制是否显示模态内容。
该元素仅提供基本的“模态”功能,并能够托管任意内容(像大多数WPF控件一样)。例如,如果您要显示的模态内容看起来像一个窗口(有标题、关闭按钮、鼠标拖动等),那么您仍然需要做一些工作。
以下是ModalContentPresenter如何满足您的要求:

它必须是模态的(当对话框打开时,其余UI应该被冻结)

ModalcontentPresenter可以放置在您的视觉层次结构中的任何级别,并且当显示模态内容时,任何位于其后面的内容都将无法访问。控件仍然会启用,并且仍会对其绑定的viewModel中的任何更改做出反应,但用户将无法使用鼠标和键盘导航和与控件交互。

对话框视图可以拥有自己的视图模型,或者至少我想给对话框视图提供一个对象实例,并将对象返回到父视图。

这个Stackoverflow答案展示了我建议您如何实现此目标。

视图应该是自己的"xaml"文件

主内容和模态内容均可使用内联xaml或单独的xaml文件(例如UserControl)定义。

.NET的dialogresult功能,或者至少一种获取用户在对话框中单击的响应的方法

上面的链接回答展示了如何从你的模态内容中获取一个“答案”。基本原则是你的视图模型正常通信(直接或通过其他方式,如事件总线)。唯一的区别是你只是以一种方式“显示”你的内容,这意味着用户只能与“模态”数据交互。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接