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?