Fede's answer is absolutely right, but I think there's an even better and more MVVM-friendly way to do this just by extending your Window
class a bit:
#region bool PreventClose dependency property
public static readonly DependencyProperty PreventCloseProperty = DependencyProperty.Register(
"PreventClose",
typeof(bool),
typeof(MainWindow),
new PropertyMetadata(false));
public bool PreventClose
{
get
{
return (bool)GetValue(PreventCloseProperty);
}
set
{
SetValue(PreventCloseProperty, value);
}
}
#endregion
protected override void OnClosing(CancelEventArgs e)
{
if (this.PreventClose)
{
e.Cancel = true;
return;
}
base.OnClosing(e);
}
Now you can just bind your new PreventClose
property in XAML to some corresponding property on the view model. The actual application logic determining whether the window should be allowed to close still remains in the view model where it belongs, but the separation between view and view model is cleaner now because the GUI code no longer depends on any view model specifics.
This really goes to defining exactly what we mean by "code-behind" vs. "application logic". I hate semantic arguments (most of all on this site), but some erroneously define the "application logic" to mean nothing more than CRUD, then argue that all logic relevant to the user interface goes in the view, and define this to be synonymous with "code-behind". But this is not how those terms were understood when they were first introduced. (See, e.g., Introduction to Model/View/ViewModel pattern for building WPF apps (2005) - the first known article about the pattern).
As that article explains, abstract UI/application logic that isn't specific to the GUI implementation goes in the view model. Data-heavy "business logic", such as CRUD operations, go in the "model" (which I like to call "data model" to limit the potential for confusion). The "view" should by and large do nothing more than lay out the controls and bindings between them and the view model.
"Code-behind" is a mutant hybrid of view and view model that MVVM strives to avoid as it comingles the very parts of the application that we're trying to separate. Note this is not the same as using C# code to customize or extend controls (as in my example), assuming it's done in an application-agnostic way; that kind of code is just GUI implementation, to which MVVM is agnostic.
In the OP's example, the Window (or rather the extension method) needs to know specifics about the view model - or at least an interface it implements - in order to work. It basically suffers from the same issue as generic code-behind (despite being an extension method instead of a partial class
) - the clean separation between view and view model MVVM strives for is thus destroyed.
In my example, we extend Window
in a completely application-agnostic way. You could take this subclassed Window
and plop it in a WPF helper library to use for the rest of your career. And since it's a bindable property, you can hook up the view model and view cleanly through a simple declarative binding.
Ultimately, it's not about whether the view layer contains C# code; it's what that C# code does that matters. If you keep view-layer C# code limited to the GUI implementation and application-agnostic, it's not just ok - but is encouraged - to use that to implement rich interactive UIs. But when it comes time to finally connect your rich interactive UI to your abstract view model, strive to keep those connection points limited to declarative bindings rather than allowing imperative GUI code to directly interact with or become dependent on your application-specific logic. That's how you stay faithful to the pattern and realize its full range of benefits.