【问题标题】:Using MVVM show new window and get updates data使用 MVVM 显示新窗口并获取更新数据
【发布时间】:2013-02-12 06:30:22
【问题描述】:

我正在开发 WPF MVVM 应用程序。我在数据网格中显示一些数据。我有两个按钮来添加和编辑选定的记录。我在 ViewModel 中有数据,我必须显示另一个窗口(视图)并确保 ViewModels 不应该有关于视图的信息。 我应该在哪里创建它的视图和视图模型? 如何取回数据并更新数据网格? 如何在 MVVM 中实现这一点? 我们还没有决定使用任何框架,所以我必须创建自己的界面。

【问题讨论】:

  • 你的“另一个窗口”像模态对话框吗?也就是说,是不是一个单独的窗口,一直保持焦点直到再次关闭,然后焦点又回到主窗口?
  • 是的,这是一个模态对话框。

标签: wpf mvvm interface modal-dialog


【解决方案1】:

注意:这最终是一个相当长的答案 - 如果有什么不清楚的地方请问我

对话窗口的实现在 MVVM 设计中是一个有争议的问题,不同的人使用不同的方法。

和你一样,我决定不使用任何框架并手动实现大多数东西。当谈到对话窗口时,我选择通过从 ViewModel 内部启动对话窗口来务实地实现 MVVM。此外,我允许每个 Dialog ViewModel 引用它所显示的 Window,因此它可以在适当的时候关闭它(详情如下)。这打破了一些严格的 MVVM “规则”,但它完成了工作。

这样做的主要缺点是,如果您正在测试通过对话框的内容,它可能会破坏单元测试。但是,您可以走很长一段路而不会遇到这个问题,而且它还没有困扰我。

我已经建立了一些对话框 ViewModel 库,我可以轻松地对其进行扩展。这里的代码太多了,但我会向您展示重点。

对话框的基本视图模型

我的每个对话窗口都有一个继承自 DialogViewModelBase 的 ViewModel,这与我的常规 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.DialogResult 属性设置后关闭。这就是为什么DialogWindowDialogViewModelBase 类的属性 - 当子类化对话框ViewModel 想要关闭对话框窗口时,它只是设置结果:

protected void CloseDialogWithResult(bool dialogWindowResult)
{
    // Setting this property automatically closes the dialog window:
    this.DialogWindow.DialogResult = dialogWindowResult;
}

对话框视图的宿主窗口

ShowDialogWindow 方法实例化的Dialogs.Views.DialogWindow 类在 XAML 中定义,是Window 的子类。它有两个重要的特点。首先是它的主要内容元素只是一个绑定到当前上下文的ContentControl。这允许我为DialogViewModelBase 的不同子类定义不同的Views,并且DialogWindow 将根据上下文的类型托管相应的View

<ContentControl Content="{Binding}" /> <!-- In reality this is inside a border etc but its simplified here for demonstration -->

DialogWindow XAML 的第二个重要特性是它定义了哪个对话框 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>

这一切的作用是,我可以将对话框定义为DialogViewModelBase 的子类,并为每个对话框实现一个View,然后告诉DialogWindow 哪个ViewContentControl 必须显示哪个对话框@987654348 @。

启动对话框并获得结果

下面是我的一个应用程序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:我真的应该写一篇关于这个的博客文章——当我这样做时,我会在这里发布链接,因为博客文章可能会有更完整的代码示例。

【讨论】:

  • 感谢您的帖子,Ryan Vice 和 Muhammad Shujaat Siddiqi 所著的 Silverligt 和 WPF 中企业架构的 MVVM 生存指南一书展示了类似的方法,并提供了更多详细信息。对于所有对这项技术感兴趣的人。
【解决方案2】:

这取决于您如何处理数据。我假设只有当用户单击保存之类的东西时才能接受在弹出窗口中所做的更改,否则它们应该被丢弃。 因此,首先,我建议使用 MVC 方法作为控制器非常适合此类任务。您在其中构建视图模型,为它们分配视图并显示视图。虚拟机只是保存数据和命令,命令执行方法保存在控制器中。换句话说,你有管理你的虚拟机和视图的单例类。 您应该查看Prism 框架。它提供了很棒的功能,例如视图区域,您可以在其中注入不同的用户控件在运行时、命令和 MVC 分层以及 IOC 和 DI 模式开箱即用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-23
    • 1970-01-01
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多