使用MVVM从WPF应用程序启动对话框/子窗口的标准方法

总而言之,我想知道使用MVVM模式从WPF启动[子]对话框/窗口的公认最佳方法/行业标准。 我遇到过以下文章:

A. CodeProject – 使用MVVM模式时显示对话框

这种方法看起来不错,但对我来说太过分 这是一定程度的代码复制,我不相信这是正确的方法。

B. WPF MVVM和显示对话框

这简要地介绍了三个选项,其中包含各种链接,这些链接在解释方法或主题方面都相当/非常差。

有人可以提供一个行业标准方法/方法的解释,从使用MVVM的WPF应用程序启动对话框,最好是一些链接到进一步的阅读材料? 如果你能自己提供一个例子我当然会非常感激!

谢谢你的时间。

首先,我不知道使用MVVM显示对话框的任何“行业标准”方式,因为没有这样的东西。
其次,欢迎使用MVVM,您刚刚介绍了MVVM没有标准的领域。
说实话,MVVM有很多痛点,这就是为什么有很多MVVM框架的原因,仅举几个MVVM Light,PRISM,Caliburn.Micro,Cinch,Catel,WAF,Baboon,shell i停止或你想要更多。
现在回答你的问题,在处理了大部分框架后,我注意到了一个共性,他们都使用了DI / IoC容器,然后为你提供了一个接口,比如IDialogManager和他们自己的实现,然后他们问你在视图模型中接受此接口并使用它来显示对话框。 总结一下,我会使用dependency injection,有一个界面来显示对话框,然后提供和实现它,并将其注册到di容器,然后从我的视图模型或视图中使用它。
编辑:所以你选择了PRISM (我认为)在显示对话框之间最难。 现在除此之外,通过使用交互请求 (检查文章的中间部分)有一种困难的方法,或者您可以使用此答案作为一种更快捷的方式。

最近,我为WPF实现了自己的导航服务,它使用了Caliburn.Micro的WindowManager(但你可以用别的东西替换它)。

示例(如何使用):

_navigationService.GetWindow() .WithParam(vm => vm.IsEditing, true) .WithParam(vm => vm.Client, SelectedClient) .DoIfSuccess(() => RefreshSelectedClient()) .ShowWindowModal(); 

执行:

 namespace ClientApplication.Utilities { public class NavigationService : INavigationService { SimpleContainer _container; IWindowManager _windowManager; public NavigationService(SimpleContainer container, IWindowManager windowManager) { _container = container; _windowManager = windowManager; } public INavigationService GetWindow() { return new NavigationService(_windowManager, (TViewModel)_container.GetInstance(typeof(TViewModel), null)); } } public class NavigationService : INavigationService { IWindowManager _windowManager; TVM _viewModel; System.Action _action; public NavigationService(IWindowManager windowManager, TVM viewModel) { _windowManager = windowManager; _viewModel = viewModel; } public INavigationService WithParam(Expression> property, TProperty value) { var prop = (PropertyInfo)((MemberExpression)property.Body).Member; prop.SetValue(_viewModel, value, null); return this; } public INavigationService DoBeforeShow(Action action) { action(_viewModel); return this; } public INavigationService DoIfSuccess(System.Action action) { _action = action; return this; } public void ShowWindow(IDictionary settings = null) { _windowManager.ShowWindow(_viewModel, null, settings); } public bool ShowWindowModal(IDictionary settings = null) { bool result = _windowManager.ShowDialog(_viewModel, null, settings) ?? false; if (result && _action != null) _action(); return result; } } } 

接口:

 namespace Common { public interface INavigationService { INavigationService WithParam(Expression> property, TProperty value); INavigationService DoIfSuccess(System.Action action); INavigationService DoBeforeShow(Action action); void ShowWindow(IDictionary settings = null); bool ShowWindowModal(IDictionary settings = null); } public interface INavigationService { INavigationService GetWindow(); } } 

最新版本的Prism( 此处下载 )包含一个名为“Stock Trader”的MVVM应用程序的所谓“参考实现”。 我的理由是,如果Prism团队称其为“参考实现”,那么从他们的角度来看这是最“标准”(如果MVVM中的任何内容都是标准的),并且是合理的选择。

源包含一个用于引发modal dialog的基础结构库,它非常好。 所以我采用了该库并成功部署了它(我将这样的应用程序上传到Codeplex)。

我需要将代码调整为1将父级图标添加到标题栏,因为库没有提供它; 并且[2]将一些有意义的文本添加到标题栏,因为库将其留空并[3]添加一个委托以在对话框关闭时调用。 它被抽象到VM可以通过将两个字符串(即Unity注册名称)传递给中介来引发对话的程度。 Codeplex上提供了这些更改。

因此,在所有其他“标准”中,“参考实施”应该作为一种可行的选择进行最低限度的参与。 对你的问题更倾斜的答案是,如果你的视图模型被充分隔离并完全通过POCO接口工作,那么在理论中,它应该无关紧要,因为切换到另一个“标准”应该是一个微不足道的练习。

创建一个对话框服务对我来说很好,并且在你的链接中也有建议。

后来我在Gill Cleeren的MVVM演示中的开发日看到了相同的解决方案。 检查链接是否有工作代码示例(尽管是为Metro编写的)

只有让我了解一下对话服务的一点是,它在某种程度上依赖于UI技术(富客户端)。

一个简单的请求 – 响应Web前端View可以构建在WPF XAML绑定的相同ViewModel和Model代码之上。 直到ViewModel开始通过对话框服务弹出对话框。 我不知道如何为Web视图实现对话服务。 实现对话框需要向视图推送更多逻辑。

我只是使用对话服务,请看这里

在您的viewmodel中,您只需要:

 var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM); ... do anything with the dialog result... 

使用接口实现对话框的目的是使代码可测试。 在这种情况下,“A”被广泛使用,但仍然很难说“标准”。 如果您没有对ViewModel进行测试,或者您可以测试ViewModel避免触摸对话框,例如使用Extract-Override,则绝对不能按照说明进行操作。