According to my understanding of MVVM, it is a good practice to handle routed commands directly in the ViewModel.
When a routed command is defined in a ViewModel as a RelayCommand (or DelegateCommand), it is easy to bind directly to the command like this: Command={Binding MyViewModelDefinedCommand}.
Actually, for routed command that are defined outside of my ViewModel, I handle those commands in the Code behind of the View and forward calls to the ViewModel. But I find it awkward that I have to do so. It goes against recommended MVVM good practices. I think that there should be a more elegant way to achieve the job.
How can I handle a "System.Windows.Input.ApplicationCommands" or any routed command defined outside of the Viewmodel directly in the ViewModel. In other words, for command defined outside of the ViewModel, how can I handle CommandBinding callback "CommandExecute" and/or "CommandCanExecute" to the ViewModel directly? Is that possible or not? If yes how? If no, why?
Here i have a simple example for Binding a Command to a button:
MainWindow.xaml
MainWindow.xaml.cs
MainWindowViewModel.cs
The accepted answer is very nice, but it seems the OP didn't quite understand how RoutedCommands work and that caused some confusion. Quoting from the question:
This is ambigous, but either way it's incorrect:
RoutedCommand is a specific implementation of ICommand
RoutedCommand's Execute/CanExecute methods do not contain our application logic (when you instantiate a RoutedCommand, you don't pass Execute/CanExecute delegates). They raise routed events which, like other routed events, traverse the element tree. These events (PreviewCanExecute, CanExecute, PreviewExecuted, Executed) are looking for element that has CommandBinding for that RoutedCommand. CommandBinding object has event handlers for those events, and that is where our application logic goes (now it's clear why exposing a RoutedCommand from your VM doesn't solve the issue).
xaml:
CommandBinding object
CommandBinding class does not inherit from DependencyObject (it's Command property can't be bound to a command exposed on VM). You can use event handlers attached to a CommandBinding to forward the call (in code-behind) to the VM - there is nothing important there, no logic (nothing to test). If you want no code-behind, then the accepted answer has nice solution (does that forwarding for you).
I would rephrase the question as:
To which, I would respond: Great Question!
WPF does not provide a built-in way to do this, which is especially annoying when you're first starting WPF and everybody tells you that "Code-Behind is evil" (it really is). So you have to build it yourself.
Building it Ourselves
So, how do go about creating such functionality ourselves? Well, first we need an equivalent of a
CommandBinding
:And then we need a class that will actually associated the RoutedCommandHandler with a specific element. For this, we'll make a collection of
RoutedCommandHandler
s as an attached property, like so:Then, it's as simple as using the classes on our element:
Interaction.Behavior implementation
Knowing the above, you might then ask:
To which, I would respond: Great Question!
If you're already using Interaction.Behaviors, then you can use the following implementation instead:
With the corresponding XAML: