WPF:从模型 MVVM 关闭窗口
本文关键字:窗口 MVVM 模型 WPF | 更新日期: 2023-09-27 18:37:06
我正在尝试从其ViewModel关闭窗口。我正在使用 MVVM 模式。我已经厌倦了使用窗户;
Window parentWindow = Window.GetWindow(this);
但是我不能这样做,我如何获取视图模型的窗口以便我能够关闭窗口。我希望能够在代码中执行此操作。
你能在代码中找到父窗口吗?
ViewModels
不应该以任何方式引用View
,包括关闭窗口,在MVVM中。
相反,View
和ViewModel
之间的通信通常是通过某种事件或消息传递系统完成的,例如Microsoft Prism的EventAggregator
或MVVM Light的Messenger
例如,View
应该订阅侦听类型为 CloseWindow
的事件消息,当它收到其中一条消息时,它应该自行关闭。然后,ViewModel
只需在它想要告诉View
关闭时广播CloseWindow
消息。
MVVM 中事件系统的简要概述,以及一些示例,如果您有兴趣,请参阅我关于 ViewModels 之间的通信的博客文章
是的,在视图模型中引用视图不是最佳实践。为什么?因为当你对视图模型进行单元测试时,需要你实例化视图,对于小视图来说并不难做到这一点,但对于一个具有复杂依赖树的复杂视图呢? 那不会很好。
对我来说,与视图进行通信的最简单方法是在ViewModel构造函数上传递IInputElement
。 IInputElement
的好处是路由事件主干,它具有路由事件所需的RaiseEvent
和AddHandler
方法。 因此,您可以自由地将事件冒泡/隧道/直接到应用程序上的任何视图或视图模型,而无需任何额外的库。
这是我在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/