WPF:从模型 MVVM 关闭窗口

本文关键字:窗口 MVVM 模型 WPF | 更新日期: 2023-09-27 18:37:06

我正在尝试从其ViewModel关闭窗口。我正在使用 MVVM 模式。我已经厌倦了使用窗户;

Window parentWindow = Window.GetWindow(this);

但是我不能这样做,我如何获取视图模型的窗口以便我能够关闭窗口。我希望能够在代码中执行此操作。

你能在代码中找到父窗口吗?

WPF:从模型 MVVM 关闭窗口

ViewModels不应该以任何方式

引用View,包括关闭窗口,在MVVM中。

相反,ViewViewModel之间的通信通常是通过某种事件或消息传递系统完成的,例如Microsoft Prism的EventAggregator或MVVM Light的Messenger

例如,View应该订阅侦听类型为 CloseWindow 的事件消息,当它收到其中一条消息时,它应该自行关闭。然后,ViewModel只需在它想要告诉View关闭时广播CloseWindow消息。

MVVM 中事件系统的简要概述,以及一些示例,如果您有兴趣,请参阅我关于 ViewModels 之间的通信的博客文章

是的,在视图模型中引用视图不是最佳实践。为什么?因为当你对视图模型进行单元测试时,需要你实例化视图,对于小视图来说并不难做到这一点,但对于一个具有复杂依赖树的复杂视图呢? 那不会很好。

对我来说,与视图进行通信的最简单方法是在ViewModel构造函数上传递IInputElementIInputElement的好处是路由事件主干,它具有路由事件所需的RaiseEventAddHandler方法。 因此,您可以自由地将事件冒泡/隧道/直接到应用程序上的任何视图或视图模型,而无需任何额外的库。

这是我在ViewModel上的简化代码,但请记住,此技术仅适用于视图优先方法

public class MyViewModel : INotifyPropertyChanged
{
    public static readonly RoutedEvent RequestCloseEvent = EventManager.RegisterRoutedEvent("RequestClose",
        RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyViewModel));
    private IInputElement dispatcher;
    public MyViewModel(IInputElement dispatcher)
    {
        this.dispatcher = dispatcher;
    }
    public void CloseApplication()
    {
        dispatcher.RaiseEvent(new RoutedEventArgs(RequestCloseEvent));
    }
}

在您的视图上

DataContext = new MyViewModel(this)
//notice "this" on the constructor

和应用程序的根视图(窗口)简单

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        AddHandler(MyViewModel.RequestCloseEvent, new RoutedEventHandler(onRequestClose));
    }
    private void onRequestClose(object sender, RoutedEventArgs e)
    {
        if (MessageBox.Show("Are you sure you want to quit?", "Confirmation", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
        {
            Close();
        }
    }
}

而且由于IInputElement是接口而不是类,因此您可以轻松地为单元测试创建模拟类

var target = new MyViewModel(new DispatcherMock)

或者你可以使用模拟库,如RhinoMocks。

如需进一步阅读,您可以详细了解如何使用路由事件

如果确实需要,请让 ViewModel 执行此操作。

例如,模型说,不再有有效的数据

将该信息传递给视图模型

视图模型识别,它不能再显示任何内容

然后关闭窗口。

空视图是表示没有更多数据的正常方式

您可以在视图模型中定义操作

public Action CloseAction { get; set; }

然后,在窗口中(例如在 DataContextChanged 中),您可以设置此操作:

((IClosable)viewModel.Content).CloseAction = () => System.Windows.Application.Current.Dispatcher.Invoke(Close());

好吧,所有这些都是更大的依赖注入模式的一部分,但基本原则在这里......接下来,只需从 VM 调用操作。

此任务有一个有用的行为,它不会破坏 MVVM,这是表达式混合 3 引入的行为,允许视图挂钩到完全在 ViewModel 中定义的命令中。

此行为演示了允许 视图模型,用于在 模型-视图-视图模型应用程序。

这允许您在视图(用户控件)中挂接行为,该行为 将提供对控件窗口的控制,允许视图模型 以控制是否可以通过标准 ICommand 关闭窗口。

使用行为允许视图模型在 M-V-VM 中管理视图生存期

http://gallery.expression.microsoft.com/WindowCloseBehavior/