wpf 使用 MVVM 显示新窗口并获取更新数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14826765/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using MVVM show new window and get updates data
提问by Omer
I'm working on a WPF MVVM application. I'm showing some data in a datagrid. I've two buttons to Add and Edit the selected record. I've data in ViewModel and I've to show another window (view) and make sure that ViewModels should have no information about views. Where should I create its view and viewmodel? How to get the data back and update datagrid? How can I achieve this in MVVM? We have not yet decided to use any framework, so I've to create my own interface.
我正在开发 WPF MVVM 应用程序。我在数据网格中显示一些数据。我有两个按钮可以添加和编辑所选记录。我在 ViewModel 中有数据,我必须显示另一个窗口(视图)并确保 ViewModel 不应该有关于视图的信息。我应该在哪里创建它的视图和视图模型?如何取回数据并更新数据网格?如何在 MVVM 中实现这一点?我们还没有决定使用任何框架,所以我必须创建自己的界面。
回答by Pieter Müller
Note: This ended up being quite a long answer - please ask me if anything is unclear
注意:这最终是一个很长的答案 - 如果有什么不清楚的,请问我
The implementation of dialog windows is a contentious issue in MVVM designs, and different people use different approaches.
对话窗口的实现在 MVVM 设计中是一个有争议的问题,不同的人使用不同的方法。
Like you, I've decided not to use any framework and implement most things by hand. When it comes to dialog windows, I choose to be pragmatic about my implementation of MVVM, by launching the Dialog Window from inside my ViewModel. Also, I allow each Dialog ViewModel to have a reference to the Window it is displayed in, so it can close it when appropriate (details below). This breaks some of the strict MVVM "rules", but it gets the job done.
和你一样,我决定不使用任何框架,而是手工实现大部分事情。当谈到对话框窗口时,我选择务实地实现 MVVM,方法是从我的 ViewModel 内部启动对话框窗口。此外,我允许每个 Dialog ViewModel 引用它所显示的窗口,因此它可以在适当的时候关闭它(详情如下)。这打破了一些严格的 MVVM“规则”,但它完成了工作。
The main downside of this is that it might break unit testing if you are testing something that goes through a dialog. However, you can go a long way without running into that problem and it has not bothered me yet.
这样做的主要缺点是,如果您正在测试通过对话框的内容,它可能会破坏单元测试。但是,您可以走很长的路而不会遇到那个问题,而且它还没有困扰我。
I've built up a bit of a library of dialog ViewModels which I can easily extend. It's way too much code to post here, but I'll show you the highlights.
我已经建立了一些可以轻松扩展的对话框 ViewModels 库。在这里发布的代码太多了,但我会向您展示亮点。
Base ViewModel for Dialogs
对话框的基本视图模型
Each of my dialog windows has a ViewModel that inherits from DialogViewModelBase, which is similiar to my regular ViewModelBasein that it provides support for INotifyPropertyChangedetc. The interesting part is this public method, which I call from wherever to launch the Dialog:
我的每个对话框窗口都有一个继承自 的 ViewModel DialogViewModelBase,它类似于我的常规ViewModelBase,因为它提供对INotifyPropertyChanged等的支持。有趣的部分是这个公共方法,我从任何地方调用它来启动对话框:
/// <summary>
/// Creates window instance for this dialog viewmodel and displays it, getting the dialog result.
/// </summary>
public void ShowDialogWindow()
{
// This is a property of the DialogViewModelBase class - thus, each DialogViewModel holds a reference to its own DialogWindow:
this.DialogWindow = new Dialogs.Views.DialogWindow();
// Tell the DialogWindow to display this ViewModel:
this.DialogWindow.DataContext = this;
// Launch the Window, using a method of the Window baseclass, that only returns when the window is closed:
this.DialogWindow.ShowDialog();
}
Window launched in the above method will close when its Window.DialogResultproperty is set. This is why the DialogWindowis a property of the DialogViewModelBaseclass - when the subclassing dialog ViewModelwants to close the dialog window, it simply sets the result:
以上述方法启动的窗口将在Window.DialogResult设置其属性时关闭。这就是为什么DialogWindow是DialogViewModelBase类的属性- 当子类化对话框ViewModel想要关闭对话框窗口时,它只是设置结果:
protected void CloseDialogWithResult(bool dialogWindowResult)
{
// Setting this property automatically closes the dialog window:
this.DialogWindow.DialogResult = dialogWindowResult;
}
Host Window for Dialog Views
对话框视图的宿主窗口
The Dialogs.Views.DialogWindowclass that the ShowDialogWindowmethod instantiates is defined in XAML and is a subclass of Window. It has two important features. The first is that it's primary content element is simply a ContentControlthat binds to the current context. This allows me to define different Viewsfor different subclasses of DialogViewModelBase, and the DialogWindowwill host the corresponding Viewbased on the type of the context:
该方法实例化的Dialogs.Views.DialogWindow类ShowDialogWindow是在 XAML 中定义的,并且是Window. 它有两个重要的特点。第一个是它的主要内容元素只是一个ContentControl绑定到当前上下文的元素。这允许我Views为 的不同子类定义不同的DialogViewModelBase,并且DialogWindow将View根据上下文的类型托管相应的:
<ContentControl Content="{Binding}" /> <!-- In reality this is inside a border etc but its simplified here for demonstration -->
The second important feature of the DialogWindowXAML is that it defines which dialog Viewsgo with which dialog ViewModels. Here is a sample:
DialogWindowXAML的第二个重要特性是它定义了哪个对话框Views与哪个对话框配合ViewModels。这是一个示例:
<Window.Resources>
<!-- DEFAULT ViewModel-View TEMPLATES -->
<DataTemplate DataType="{x:Type dialogs:YesNoMessageBoxDialogViewModel}">
<views:MessageBoxView />
</DataTemplate>
<DataTemplate DataType="{x:Type dialogs:ErrorDialogViewModel}">
<views:ErrorDialogView/>
</DataTemplate>
</Window.Resources>
What all this does, is that I can define dialogs as subclasses to DialogViewModelBaseand implement a Viewfor each, and then tell DialogWindowwhich Viewits ContentControlmust show for which dialog ViewModel.
所有这一切呢,是我可以定义对话框作为子类DialogViewModelBase,并实现View每一个,然后告诉DialogWindow它View其ContentControl为哪个对话框必须显示ViewModel。
Launching a Dialog and getting results
启动对话框并获得结果
Below is a sample from one of my application ViewModels, in which I launch a Dialog Window that allows the user to select an Asset Type for creation:
下面是我的一个应用程序的示例,我ViewModels在其中启动了一个对话框窗口,允许用户选择要创建的资产类型:
public void CreateNewAsset()
{
// Instantiate desired Dialog ViewModel:
Dialogs.NewAssetTypeSelectionDialogViewModel dialog = new Dialogs.NewAssetTypeSelectionDialogViewModel();
// Launch Dialog by calling method on Dialog base class:
dialog.ShowDialogWindow();
// Execution will halt here until the Dialog window closes...
// The user's selection is stored in a property on the dialog ViewModel, and can now be retrieved:
CalculatorBase.AssetTypeEnum newAssetType = dialog.AssetType;
switch (newAssetType)
{
// Do stuff based on user's selection...
}
}
PS: I should really write a blog entry about this - when I do, I will post the link here, as the blog entry will probably have more complete code samples.
PS:我真的应该写一篇关于这个的博客条目——当我这样做的时候,我会在这里发布链接,因为博客条目可能会有更完整的代码示例。
回答by Vidas Vasiliauskas
It depends how you are handling the data. I will assume that changes made in the popup window can be accepted only when user clicks something like save in other case they should be discarded. So firstly, I would suggest using MVC approach as controller is perfect for such tasks. You build viewmodels in it, assign them o views and show the views. VM's simply keeps data and commands, commands execute methods are kept in controller. In other words you have singleton class which manages your VM's and views. You should check out Prismframework. It offers great things like view regios where you can inject different user controls on the runtime, commanding and MVC layering out of the box alongside IOC and DI patterns.
这取决于您如何处理数据。我将假设只有当用户单击保存在其他情况下它们应该被丢弃时,才可以接受在弹出窗口中所做的更改。所以首先,我建议使用 MVC 方法作为控制器非常适合此类任务。您在其中构建视图模型,将它们分配给视图并显示视图。VM 只是保存数据和命令,命令执行方法保存在控制器中。换句话说,你有一个单例类来管理你的虚拟机和视图。您应该查看Prism框架。它提供了一些很棒的东西,比如视图区域,你可以在运行时注入不同的用户控件,命令和 MVC 分层以及 IOC 和 DI 模式开箱即用。

