【问题标题】:How to manage multiple windows in MVVM如何在 MVVM 中管理多个窗口
【发布时间】:2014-02-14 10:15:27
【问题描述】:

我知道有几个与此类似的问题,但是我还没有找到明确的答案。我正在尝试使用 MVVM,并尽可能保持纯净,但不确定如何在坚持模式的同时准确地启动/关闭窗口。

我最初的想法是数据绑定命令到 ViewModel 触发代码以启动一个新 View,然后通过 XAML 将 View 的 DataContext 设置为它的 ViewModel。但这违反了我认为的纯 MVVM...

经过一些谷歌搜索/阅读答案后,我遇到了 WindowManager 的概念(就像在 CaliburnMicro 中一样),现在如果我要在一个普通的 MVVM 项目中实现其中一个,这是否适用于我的 ViewModels?或者只是在我的应用程序的核心?我目前正在将我的项目分成Model 程序集/项目、ViewModel 程序集/项目和View 程序集/项目。这应该进入不同的“核心”程序集吗?

这有点引出了我的下一个问题(与上述问题有些相关),我如何从 MVVM 的角度启动我的应用程序?最初我会从 App.xaml 启动我的 MainView.xaml,XAML 中的 DataContext 将附加分配的 ViewModel。如果我添加WindowManager,这是我的应用程序启动的第一件事吗?我是否从App.xaml.cs 后面的代码中执行此操作?

【问题讨论】:

  • 好问题。启动时,我通常通过 app.xaml.cs 后面的代码引导所有内容,但这总是让我觉得有点……脏。
  • 要使用多个 MVVM 样式的窗口,您可以查看我最近对该主题的 answer

标签: c# wpf xaml mvvm


【解决方案1】:

这主要取决于您的应用程序的外观(即同时打开多少个窗口,是否有模态窗口......等等)。

我给出的一般建议是不要尝试做“pure”MVVM;我经常读到诸如“应该有零代码隐藏”之类的东西,我不同意。

我目前正在将我的项目分离为模型程序集/项目, ViewModel 程序集/项目和视图程序集/项目。这应该去 进入不同的“核心”程序集?

将视图和 ViewModel 分离到不同的程序集中是您可以做的最好的事情,以确保您永远不会引用与 viewModel 中的视图相关的内容。这种强烈的分离会很好。

使用两个不同的程序集将模型与 ViewModel 分离也是一个好主意,但这取决于您的模型的外观。我个人喜欢 3 层架构,所以我的模型通常是 WCF 客户端代理,并且确实存储在它们自己的程序集中。

无论如何,“核心”程序集总是一个好主意(恕我直言),但只是为了公开可以在应用程序的所有层中使用的基本实用程序方法(例如基本扩展方法......等)。

现在对于您关于视图的问题(如何显示它们......等等),我会说做简单的。就我个人而言,我喜欢在我的视图的代码隐藏中实例化我的视图模型。我也经常在我的 ViewModel 中使用 events,以便通知关联的视图它应该打开另一个视图。

例如,当用户单击按钮时,您的 MainWindow 应该显示一个子窗口:

// Main viewModel
public MainViewModel : ViewModelBase
{
    ...
    // EventArgs<T> inherits from EventArgs and contains a EventArgsData property containing the T instance
    public event EventHandler<EventArgs<MyPopupViewModel>> ConfirmationRequested;
    ...
    // Called when ICommand is executed thanks to RelayCommands
    public void DoSomething()
    {
        if (this.ConfirmationRequested != null)
        {
            var vm = new MyPopupViewModel
            {
                // Initializes property of "child" viewmodel depending
                // on the current viewModel state
            };
            this.ConfirmationRequested(this, new EventArgs<MyPopupViewModel>(vm));
        }
    }
}
...
// Main View
public partial class MainWindow : Window
{
    public public MainWindow()
    {
        this.InitializeComponent();

        // Instantiates the viewModel here
        this.ViewModel = new MainViewModel();

        // Attaches event handlers
        this.ViewModel.ConfirmationRequested += (sender, e) =>
        {
            // Shows the child Window here
            // Pass the viewModel in the constructor of the Window
            var myPopup = new PopupWindow(e.EventArgsData);
            myPopup.Show();         
        };
    }

    public MainViewModel ViewModel { get; private set; }
}

// App.xaml, starts MainWindow by setting the StartupUri
<Application x:Class="XXX.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             ...
             StartupUri="Views/MainWindow.xaml">

【讨论】:

  • 我一直倾向于在视图后面的代码中执行此操作,因为它有效地控制 UI,因此代码应该与 UI 的其余部分一起使用。但是,由于“纯”无代码隐藏的心态,我一直在避免这种情况。这可能是我的方式,具体取决于我得到的替代答案..
猜你喜欢
  • 2013-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多