【问题标题】:WPF: Managing windows (opening, closing, etc...) in MVVM?WPF:在 MVVM 中管理窗口(打开、关闭等)?
【发布时间】:2011-04-07 16:04:18
【问题描述】:

我在很多地方都读过它。大多数人指的是这两个链接:

两个我都不懂。我是 MVVM 的初学者。当谈到 MVVM 中的窗口操作时,有些人会提到控制器。这些是什么以及它们是如何实施的?根据book,MVVM 由模型、视图模型和视图组成——控制器从何而来?

如果有人可以提供以下用例的示例,那就太棒了(对于所​​有刚刚开始使用这个的人,就像我一样):

  1. 先决条件:打开一个窗口。
  2. 用户单击按钮。
  3. 新窗口打开,一些数据被传递到该窗口,即一些字符串。
  4. 新窗口关闭(或单击按钮),一些数据被传递到第一个 窗户。
  5. 传递的数据改变了窗口上的某些内容。

【问题讨论】:

    标签: wpf mvvm


    【解决方案1】:

    ViewModel 到 ViewModel 的通信通常由事件聚合器模式的实现来处理。

    MVVM Light 使用Messenger 类,Prism 有另一种实现,但基本上这是在视图模型之间发送消息而不耦合的一种方式。

    有一些例子,Articles 描述了用法。 我建议你看看它。

    关于 WPF 中的控制器的东西,我不知道。

    关于示例:

    -我有一个带有 WindowsViewModel 的 Windows。这个类应该有一个绑定到按钮的命令。

    -用户单击按钮。执行命令。

    -命令打开一个新窗口。

    在这里您应该创建对话框视图模型,并且您应该以某种方式创建窗口。或者使用 ViewModel 创建 Window,但 ViewModel 不应该对 View 了解太多,否则无法测试。

    我们使用这样的东西是因为我们有一些要求,但它 可能要简单得多,碰巧这是我手头唯一的例子:

    bool? ShowDialogImpl<TViewModel>(Action<TViewModel> setup) where TViewModel : ViewModel
    {
        return (bool?)DispatcherHelper.UIDispatcher.Invoke(
            (Func<bool?>)(() =>
            {
                var viewModel = viewModelFactory.Get<TViewModel>();
                viewModel.ViewService = this;
                setup(viewModel);
                var window = new Window
                {
                    Owner = this,
                    SizeToContent = SizeToContent.WidthAndHeight,
                    WindowStartupLocation = WindowStartupLocation.CenterOwner,
                    Content = ViewFactory.CreateView<TViewModel>(),
                    DataContext = viewModel,
                    WindowStyle = WindowStyle.ToolWindow,
                    ShowInTaskbar = false
                };
                window.SetBinding(TitleProperty, new Binding("Title"));
                openDialogs.Push(window);
                window.Activated += (sender, args) => window.SizeToContent = SizeToContent.Manual;
                var result = window.ShowDialog();
                openDialogs.Pop();
                viewModelFactory.Release(viewModel);
                return result;
            }));
    }
    

    基本上:我们创建一个窗口和一个视图模型。 视图模型是使用容器从工厂创建的。 setup Action 委托是我们数据的入口点。

    • 通讯:

    第一个 Windows 是一个 Grid,第二个 Dialog 用于编辑网格的数据。 在我们拥有的 Windows 中:

    messenger.Register<EntityUpdated<FooClass>>(this, message => UpdateItem(message.Entity));
    

    在对话框中:

    messenger.Send(new EntityUpdated<FooClass>(subject));
    

    这样,我们就知道何时在编辑对话框中更新了某些内容以刷新网格。

    希望对你有帮助:)

    【讨论】:

    • 感谢您的回复。我(还)不了解事件聚合器模式,所以我认为我需要专注于这一点才能理解您的示例。请告诉我,在您的应用程序中,当用户单击应该打开新窗口的按钮时,您是如何管理的?您是否调用添加到 ViewModel 的命令然后触发一些事件?谢谢。
    • 是的。我们尽可能使用命令。绑定到命令的方法负责调用: AddCommand = new RelayCommand(Add);其中添加: void Add() { ViewService.ShowDialog();事件聚合器就像一个中间人,将事件的订阅者与发布者分离。这样,您就可以在两个部分(订阅者和发布者)彼此不知道的情况下进行事件。
    • MVVM Light 是一种享受!我已经想通了,而且效果很好。感谢 Markust 帮助我。
    • 直接从 ViewModel 打开一个窗口似乎打破了 MVVM 意识形态。如果你这样做,你不能再简单地对你的视图模型进行单元测试。我想你会想要一个 IWindowManager 之类的东西,你可以模拟单元测试,但在非测试模式下为应用程序提供具体的窗口打开/关闭。
    • 这是一个对话框,但我同意。
    【解决方案2】:

    如果您不打算允许用户在两​​个窗口之间来回切换,而两个窗口都打开(即第一个打开第二个,而第二个必须关闭才能返回到第一个),您可以只需将两个窗口的视图模型设置为相同的视图模型实例,然后将第二个窗口作为模式打开,您来回传递的字符串将只是视图模型的属性,数据绑定到视图中的某些内容。

    【讨论】:

    • 不幸的是,我的应用程序将包含非模态窗口。另外,我打算每个视图有一个 ViewModel。感谢您分享您对该主题的想法。
    猜你喜欢
    • 2014-11-08
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 2015-03-03
    • 1970-01-01
    相关资源
    最近更新 更多