我正在尝试从其ViewModel关闭一个窗口。我正在使用MVVM模式。我已经厌倦了使用窗户;
Window parentWindow = Window.GetWindow(this);
但我无法做到这一点,我如何获得ViewModel的窗口,以便我能够关闭窗口。我希望能够在代码中执行此操作。
你能在代码中找到父窗口吗?
答案 0 :(得分:3)
ViewModels
不应以任何方式引用View
,包括在MVVM中关闭窗口。
相反,View
和ViewModel
之间的通信通常是通过某种事件或消息系统完成的,例如Microsoft Prism's EventAggregator
或MVVM Light's Messenger
例如,View
应订阅以侦听类型为CloseWindow
的事件消息,并且当它收到其中一条消息时,它应自行关闭。然后ViewModel
只需要在CloseWindow
关闭时发出View
消息即可。
如果您有兴趣,可以在我关于Communication between ViewModels的博客文章中简要概述MVVM中的事件系统,以及一些示例
答案 1 :(得分:1)
是在viewmodel中引用视图不是最佳做法。为什么? 因为当您对viewmodel进行单元测试时,它需要您实例化视图,对于小视图来说并不难做到这一点,但是对于具有复杂依赖树的复杂视图?这不会很好。
对我来说,与view进行通信的最简单方法是在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
和应用程序的根视图(Window)只是
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这样的模拟库
如需进一步阅读,您可以详细了解如何使用Routed Event
答案 2 :(得分:0)
如果确实需要,让ViewModel执行此操作。
模型说,例如,不再有效的数据
将该信息传递给ViewModel
ViewModel识别出它无法再显示任何内容
然后关闭窗口。
空视图是表示没有更多数据的正常方式
答案 3 :(得分:0)
您可以在ViewModel中定义操作
public Action CloseAction { get; set; }
然后,在您的窗口中(例如在DataContextChanged中),您可以设置此操作:
((IClosable)viewModel.Content).CloseAction = () => System.Windows.Application.Current.Dispatcher.Invoke(Close());
嗯,所有这些都是更大的依赖注入模式的一部分,但基本原则在这里...... 接下来,您需要从VM调用该操作。
答案 4 :(得分:0)
此任务有一个有用的行为,它不会破坏MVVM,一种与Expression Blend 3一起引入的行为,允许View挂钩到ViewModel中完全定义的命令。
此行为演示了一种允许使用的简单技术 ViewModel用于管理View中的结束事件 Model-View-ViewModel应用程序。
这允许您在View(UserControl)中连接一个行为 将提供对控件窗口的控制,允许ViewModel 控制是否可以通过标准ICommands关闭窗口。
Using Behaviors to Allow the ViewModel to Manage View Lifetime in M-V-VM
http://gallery.expression.microsoft.com/WindowCloseBehavior/