MVVM: Is code-behind evil or just pragmatic?

c#, code-behind, data-binding, mvvm, wpf

Solution

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

interface IClosable
{
    void Close();
}

Next, make your window implement `IClosable`:

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

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}}}" />

And lastly, the command calls `Close`:

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

And what have we now?

- 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

Problem

Imagine you want a `Save & Close` and a `Cancel & Close` button on your fancy WPF MVVM window? 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. 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(); } ``` But that is code-behind mixed in with my so far very well designed 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?

Original source

Related problems