[英]WPF: Close a Window from Model MVVM
我試圖從其ViewModel關閉一個窗口。 我正在使用MVVM模式。 我已經厭倦了使用窗戶。
Window parentWindow = Window.GetWindow(this);
但是我無法做到這一點,如何獲取ViewModel的窗口,以便能夠關閉該窗口。 我希望能夠在代碼中做到這一點。
您可以在代碼中找到父窗口嗎?
在MVVM中, ViewModels
不應以任何方式引用View
,包括關閉窗口。
相反, View
和ViewModel
之間的通信通常是通過某種事件或消息傳遞系統完成的,例如Microsoft Prism的EventAggregator
或MVVM Light的Messenger
例如, View
應訂閱以偵聽CloseWindow
類型的事件消息,並且當它收到這些消息之一時,應自行關閉。 然后,只要要告訴View
關閉, ViewModel
只需廣播CloseWindow
消息。
如果您有興趣,請在我的博客中關於ViewModels之間的通信的 MVVM中的事件系統進行簡要概述,並提供一些示例。
是的,在viewmodel中引用視圖不是最佳實踐。 為什么? 因為當您對視圖模型進行單元測試時,它要求您實例化視圖,對於小視圖而言,這樣做並不困難,但是對於具有復雜依賴樹的復雜視圖而言呢? 那不會是好事。
對我而言,與視圖進行通訊的最簡單方法是在viewmodel構造函數上傳遞IInputElement
。 IInputElement
的bennefit是路由事件主干,它具有路由事件所需的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執行此操作。
例如,模型表示不再有有效數據
將該信息傳遞給ViewModel
ViewModel認識到它無法再顯示任何內容
然后關閉窗口。
空視圖是表示沒有更多數據的正常方式
您可以在ViewModel中定義一個動作
public Action CloseAction { get; set; }
然后,在您的窗口中(例如在DataContextChanged中),您可以設置以下操作:
((IClosable)viewModel.Content).CloseAction = () => System.Windows.Application.Current.Dispatcher.Invoke(Close());
好吧,所有這些都是更大的依賴項注入模式的一部分,但是基本原理就在這里...接下來,您需要從VM調用操作。
此任務有一個有用的行為,它不會破壞MVVM,即Expression Blend 3引入的一種行為,以允許View掛接到完全在ViewModel中定義的命令中。
此行為演示了一種簡單的技術,該技術允許ViewModel在Model-View-ViewModel應用程序中管理View的關閉事件。
這使您可以在視圖(UserControl)中掛鈎行為,該行為將提供對控件窗口的控制,從而允許ViewModel控制是否可以通過標准ICommands關閉窗口。
使用行為允許ViewModel管理MV-VM中的視圖生命周期
http://gallery.expression.microsoft.com/WindowCloseBehavior/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.