使用 Prism 和 MVVM 模式在 WPF 中创建模态对话框的“漂亮”方式

Posted

技术标签:

【中文标题】使用 Prism 和 MVVM 模式在 WPF 中创建模态对话框的“漂亮”方式【英文标题】:The "pretty" way to make a modal dialog in WPF with Prism and MVVM Pattern 【发布时间】:2014-02-13 15:15:11 【问题描述】:

昨天我使用 google 找到了一些方法来使用 PRISM 4.1 和 MVVM 模式在 WPF 中制作一个很棒的可重用模式对话框。我找到了一些例子,但我必须说这些都不像我喜欢的那样“漂亮”。

这个:WPF Modal Dialog(没有 mvvm -> 没用)

这非常好:Showing Dialogs when using the MVVM Pattern(但它仍然使用自制的 ServiceLocator,因为我使用的是 IUnity Container,所以我不需要它。我可以使用逻辑并将其重写为 Unity,但这不是“漂亮”以我的诚实观点。

在网上搜索信息一段时间后,一些博客(现在找不到源代码)告诉我,PRISM 框架有一个叫做“交互请求”的东西。因此,我查看了 prism 文档,并在“高级 mvvm 场景”主题下找到了一小部分,但文档中提供的信息还不够。

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

编辑: 关于cmets中的问题:

是什么让模态对话框很棒?

确实是个好问题。

    它必须是模态的(对话框打开时 UI 的其余部分 应该被冻结) 对话框视图可以有自己的视图模型或 至少我想给对话框一个对象的实例 查看并将对象返回到父视图 视图应该是一个自己的“xaml”文件 .NET 或 at 的 dialogresult 功能 至少有一种方法可以响应用户在对话框中单击的内容

【问题讨论】:

嗯...是什么让模态对话框很棒? Ô.o 如果您能提供比这更多的技术要求,比如 awesome 请求,那就太好了。 ;) 我编辑了我的问题并回答了您的问题 您在编辑中发布的功能列表是否已经存在于基本 WPF 中(不涉及 PRISM)? Window.ShowDialog() 不会冻结 UI。相反,它通过禁用它来阻止用户输入进入父窗口,然后启动嵌套的模式消息循环(新的Dispatcher 框架)。所有这些都发生在同一个 UI 线程上。因此,它的行为与 WinForms Form.ShowDialog() 非常相似。 @darkdog,冻结 UI 和禁用它是两件不同的事情。调用 Thread.Sleep(10000) 会冻结整个 UI。调用Window.ShowDialog() 将禁止用户输入进入父窗口,但不会冻结它。您甚至可以从模式对话框更新父窗口的 UI。打开 Visual Studio 并从菜单中执行 Help About,是您要查找的对话框类型吗? 【参考方案1】:

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>

【讨论】:

这让我朝着正确的方向前进,但会受益于更多的上下文:Interactivity QuickStart Using the Prism Library 5.0 for WPF。【参考方案2】:

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

我在 Karl Shifflett 的 MVVM In The Box 训练扩展中看到了如何使用 Prism 执行此操作的示例。

我记得,这个例子的边缘相当粗糙,但它应该让你朝着正确的方向前进。

这种视图内“对话框”的问题是它不允许对话框超出父窗口的范围。从好的方面来说,你可以做很多花哨的布局和动画。

【讨论】:

maeh.. 这个 vs2010 模板 >: 必须为此安装 2010 :( 您真正需要的只是源文件,您不必安装它。博客上有一个 SkyDrive 链接,其中的第二个 Zip 文件有代码。交互请求的东西在MVVMTraining\Acme Common\Acme.Prism\InteractionRequest 这就是我要找的! 一个警告 - 该代码非常笨拙,尤其是在禁用网格上的其他控件时。在其他地方可能有更好的例子来说明如何做到这一点。我在视图中使用了一个特殊的 InteractionContentControl,而不是 Grid。【参考方案3】:

查看我来自here的帖子

它的简单、它的 mvvm、它的服务以及在你的视图模型中“你所要做的一切”是:

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

【讨论】:

公平地说,我最近添加了一些重载以得到更多类似:bool? ShowDialog(字符串标题,对象数据上下文,双 minHeigth = 0,双 minWidth = 0,双 maxHeigth = double.PositiveInfinity,双 maxWidth = double.PositiveInfinity);还是布尔? ShowDialog(string title, object datacontext, ApplicationSettingsBase settings, string pathHeigthSetting, string pathWidthSetting, double minHeigth = 0, double minWidth = 0, double maxHeigth = double.PositiveInfinity, double maxWidth = double.PositiveInfinity); 对话框服务方法很差,因为... a) 没有办法为对话框选择父窗口,b) 应该由视图决定如何显示通知给用户。通过使用对话服务,您将完全排除图片中的视图。 在我的 mvvm 应用程序中,VIEWMODEL 决定何时打开模态对话框,而 modaldialogviewmodel 的 DATATEMPLATE 决定模态对话框的外观。 modaldialog 的父级只是应用程序主窗口。所以我没有看到一个糟糕的方法,而是一个简单的方法:) 如果你有两个***窗口怎么办? 我没有这种情况,但是当您在第二个***窗口上打开模态对话框时会发生什么 - 您不想或想要访问第一个***窗口,而您的模态对话框打开了吗?【参考方案4】:

警告:我没有使用 PRISM,我的回答假设只使用 WPF 和 MVVM。我不认为这是一个主要问题,因为您的要求列表可以在没有 PRISM 的情况下得到满足(无论如何,它可以在以后添加到基本解决方案之上)。

我在Github 上有一个项目,它提供了一个名为ModalContentPresenter 的自定义FrameworkElement,它允许显示模态内容。该元素基本上由两个窗格组成,一个层叠在另一个之上。后窗格托管您的主要内容,前窗格托管您的模态内容。该元素有一个依赖属性,它控制是否显示模态内容。

该元素仅提供基本的“模态”功能,并且能够承载任意内容(如大多数 WPF 控件)。例如,如果您显示的模态内容看起来和行为都像一个窗口(有标题、关闭按钮、鼠标拖动等),那么您仍然需要做一些工作。

ModalContentPresenter 如何满足您的要求:

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

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

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

This *** answer 展示了我建议您如何实现这一目标。

视图应该是一个自己的“xaml”文件

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

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

上面的链接答案显示了如何从您的模态内容中获得“答案”。基本前提是您的 viewModel 可以正常通信(直接或通过事件总线等其他方式)。唯一的区别是您恰好以一种方式显示您的内容,这意味着用户只能与“模态”数据进行交互。

【讨论】:

以上是关于使用 Prism 和 MVVM 模式在 WPF 中创建模态对话框的“漂亮”方式的主要内容,如果未能解决你的问题,请参考以下文章

C# WPF MVVM模式Prism框架从零搭建(经典)

WPF Prism框架下基于MVVM模式的命令绑定事件

C# WPF MVVM模式Prism框架从零搭建(经典)

C# WPF MVVM模式Prism框架下事件发布与订阅

在 WPF PRISM/MVVM 应用程序中避免内存泄漏的最佳方法是啥

无法使用 PRISM 5、MVVM 和 EF 6 在 WPF 中刷新 DataGrid