MVVM:代码隐藏的邪恶还是务实的?

Dee*_*ena 5 c# data-binding wpf code-behind mvvm

想象一下,你想要一个Save & CloseCancel & Close你的花式WPF MVVM窗口上的按钮?

你会怎么做?MVVM规定你将按钮绑定到ICommand控制器的反转并指示你View可能知道你的ViewModel但不是相反.

我在网上找到了一个解决方案,它有一个ViewModel结束事件,View订阅如下:

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();
}
Run Code Online (Sandbox Code Playgroud)

但是这与我迄今为止设计良好的MVVM混合在一起.

另一个问题是在显示主窗口时显示许可问题消息框.我可以再次使用Window.Loaded像我上面那样的事件,但这也打破了MVVM,不是吗?

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

Hau*_*ger 7

首先,创建一个仅包含Close方法的接口:

interface IClosable
{
    void Close();
}
Run Code Online (Sandbox Code Playgroud)

接下来,使您的窗口实现IClosable:

class MyWindow : Window, IClosable
{
    public MyWindow()
    {
        InitializeComponent();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后让视图将自身作为IClosable命令参数传递给视图模型:

<Button Command="{Binding CloseCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
Run Code Online (Sandbox Code Playgroud)

最后,命令调用Close:

CloseCommand = new DelegateCommand<IClosable>( view => view.Close() );
Run Code Online (Sandbox Code Playgroud)

我们现在有什么?

  • 我们有一个关闭窗口的按钮
  • 我们在代码隐藏中没有代码,除了 , IClosable
  • 视图模型对视图一无所知,它只是获取一个可以关闭的任意对象
  • 该命令可以很容易地进行单元测试