WPF:从模型MVVM关闭一个窗口

时间:2012-06-14 15:12:09

标签: c# .net wpf mvvm

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

Window parentWindow = Window.GetWindow(this);

但我无法做到这一点,我如何获得ViewModel的窗口,以便我能够关闭窗口。我希望能够在代码中执行此操作。

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

5 个答案:

答案 0 :(得分:3)

ViewModels不应以任何方式引用View,包括在MVVM中关闭窗口。

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

例如,View应订阅以侦听类型为CloseWindow的事件消息,并且当它收到其中一条消息时,它应自行关闭。然后ViewModel只需要在CloseWindow关闭时发出View消息即可。

如果您有兴趣,可以在我关于Communication between ViewModels的博客文章中简要概述MVVM中的事件系统,以及一些示例

答案 1 :(得分:1)

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

对我来说,与view进行通信的最简单方法是在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

和应用程序的根视图(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/