MVVM:是代码隐藏还是务实?

MVVM:是代码隐藏还是务实?

问题描述:

想象一下,你想要一个 Save&关闭取消&关闭按钮在您的WPF MVVM窗口?

Imagine you want a Save & Close and a Cancel & Close button on your fancy WPF MVVM window?

你会怎么样? MVVM规定你将按钮绑定到一个 ICommand ,反转控制决定你的视图可能会知道你的 ViewModel ,而不是其他方式。

How would you go about it? MVVM dictates that you bind the button to an ICommand and inversion of control dictates that your View may know your ViewModel but not the other way around.

在网络周围,我发现一个解决方案有一个 ViewModel 关闭事件,查看订阅如下:

Poking around the net I found a solution that has a ViewModel closing event to which the View subscribes to like this:

private void OnLoaded(Object sender
    , RoutedEventArgs e)
{
    IFilterViewModel viewModel = (IFilterViewModel)DataContext;
    viewModel.Closing += OnViewModelClosing;
}

private void OnViewModelClosing(Object sender
    , EventArgs<Result> e)
{
    IFilterViewModel viewModel = (IFilterViewModel)DataContext;
    viewModel.Closing -= OnViewModelClosing;
    DialogResult = (e.Value == Result.OK) ? true : false;
    Close();
}

但这是代码隐藏与我迄今为止非常精心设计的MVVM 。

But that is code-behind mixed in with my so far very well designed MVVM.

显示主窗口时,另一个问题将显示许可问题消息框。再次,我可以使用如上所述的窗口加载事件,但这也是打破MVVM,是吗?

Another problem would be showing a licensing problem message box upon showing the main window. Again I could use the Window.Loaded event like I did above, but that's also breaking MVVM, is it not?

在这些情况下,是否有干净的方式或应该是实用的而不是迂腐的?

Is there a clean way or should one be pragmatical instead of pedantic in these cases?

首先,创建一个仅包含关闭方法的界面:

First, create an interface that contains only the Close method:

interface IClosable
{
    void Close();
}

接下来,让你的窗口实现 IClosable

Next, make your window implement IClosable:

class MyWindow : Window, IClosable
{
    public MyWindow()
    {
        InitializeComponent();
    }
}

然后让视图传递为 IClosable 作为视图模型的命令参数:

Then let the view pass itself as IClosable as command parameter to the view model:

<Button Command="{Binding CloseCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />

最后,命令调用关闭

CloseCommand = new DelegateCommand<IClosable>( view => view.Close() );

我们现在有什么?


  • 我们有一个关闭窗口的按钮

  • 我们没有代码隐藏中的代码 ,IClosable

  • 视图模型对视图一无所知,只需获取可以关闭的任意对象

  • 命令可以轻松进行单元测试

  • we have a button that closes the window
  • we have no code in code-behind except , IClosable
  • the view model knows nothing about the view, it just gets an arbitrary object that can be closed
  • the command can easily be unit tested