簡體   English   中英

WPF:從模型MVVM關閉窗口

[英]WPF: Close a Window from Model MVVM

我試圖從其ViewModel關閉一個窗口。 我正在使用MVVM模式。 我已經厭倦了使用窗戶。

Window parentWindow = Window.GetWindow(this);

但是我無法做到這一點,如何獲取ViewModel的窗口,以便能夠關閉該窗口。 我希望能夠在代碼中做到這一點。

您可以在代碼中找到父窗口嗎?

在MVVM中, ViewModels不應以任何方式引用View ,包括關閉窗口。

相反, ViewViewModel之間的通信通常是通過某種事件或消息傳遞系統完成的,例如Microsoft Prism的EventAggregatorMVVM Light的Messenger

例如, View應訂閱以偵聽CloseWindow類型的事件消息,並且當它收到這些消息之一時,應自行關閉。 然后,只要要告訴View關閉, ViewModel只需廣播CloseWindow消息。

如果您有興趣,請在我的博客中關於ViewModels之間的通信的 MVVM中的事件系統進行簡要概述,並提供一些示例。

是的,在viewmodel中引用視圖不是最佳實踐。 為什么? 因為當您對視圖模型進行單元測試時,它要求您實例化視圖,對於小視圖而言,這樣做並不困難,但是對於具有復雜依賴樹的復雜視圖而言呢? 那不會是好事。

對我而言,與視圖進行通訊的最簡單方法是在viewmodel構造函數上傳遞IInputElement IInputElement的bennefit是路由事件主干,它具有路由事件所需的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執行此操作。

例如,模型表示不再有有效數據

將該信息傳遞給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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM