Download Command.cs
Download DelegateCommand.cs
Download DelegateCommandExample.zip
This post is part of a short series I am doing on MVVM infrastructure. In this series, I will share some thinking and code that has helped to produce cleaner, simpler MVVM code in my applications.
Related posts:
- POCOs versus DependencyObjects
- ViewModel
- DelegateCommand
- ActiveAwareCommand
In my last post I discussed my ViewModel
base class. In this post I’m going to start showing you some infrastructure around commanding.
WPF's commanding support enables you to hook up UI interactions with code without tightly coupling the two. User actions are abstracted into implementations of WPF’s ICommand
interface, which are then associated with controls that implement ICommandSource
. Essentially, it's a layer of indirection. The controls in the UI aren't intimately aware of the command logic they are connected with, and the command logic isn't aware of the controls it will be associated with.
When starting out with WPF commanding, you will soon come across the RoutedCommand
class. This particular command is yet another layer of indirection, in that its execution logic involves finding something to execute and calling that! Starting with the focused element, it searches up the visual tree for an element that has a matching CommandBinding
in itsCommandBindings
collection. If the RoutedCommand
finds a matching CommandBinding
, it executes that CommandBinding
's Executed
delegate.
Routed commands work great in certain scenarios, and are prevalent in WPF. Indeed, the only concrete ICommand
implementation that comes with WPF is the RoutedCommand
(and its subclass, RoutedUICommand
). Unfortunately, this has caused WPF commanding to become somewhat synonymous with RoutedCommand
s, which is not at all accurate.
The thing is, routed commands are not always a great fit for MVVM development. Typically the logic for your command execution belongs in the view model. For example, suppose you have a
CustomersViewModel
that maintains a list of CustomerViewModel
s, and you want to expose a command that deletes the selected customer. The logic for that command should reside in the CustomersViewModel
, since it knows best what to do when a deletion is requested.
If you were to use a RoutedCommand
, you would then need a CommandBinding
somewhere in the UI in order to connect a visual element to the DeleteCustomerCommand
. In our example, we would likely stick a CommandBinding
in the CustomersView
and associate it with the deletion command and methods on the view model. Without the CommandBinding
, the RoutedCommand
won't find a handler for the command and the Delete button will be forever disabled.
Using routed commands with MVVM ends up being messy, sub-optimal, and requires the view be more tightly coupled to the view model. And in some scenarios, it’s not even possible (I’ll discuss such a scenario in my next post). But the good news is, we don't have to use routed commands. All we need is an appropriate implementation of ICommand – one that is more conducive to MVVM development.
If you think about it, all we really want to do is have a command that – when executed – invokes a method in our view model. And when the command is queried for its executable status, it executes a different method in the view model. To continue our customer example, that command might be associated with a
Button
in ourCustomersView
. The availability of the command would be dependent upon the user first selecting a customer (you can't delete a customer if you don't know which customer to delete). The execution of the command might execute a DeleteCustomer
method on the CustomersViewModel
.
Sound simple? That's because it is! Far simpler than attempting to use routed commands for this scenario.
The command implementation I use is called DelegateCommand
, simply because it invokes delegates when executing and querying executable status. Other people have different names for this type of command, the most common of which seems to be RelayCommand
. That's fine - call it what you will.
Prism has a DelegateCommand
too, which is almost exactly the same as this one. However, the reason I have my own is simply because we don't use Prism in our project†, and it would be a large overhead to pull it in just for the sake of a class or two. Besides, if you're doing a non-composite WPF app, Prism may not be a good fit.
To create a DelegateCommand
, you simply give it one or two delegates to use. If you give it only one delegate, the command is assumed to be always available. That is,ICommand.CanExecute()
will always return true
.
In our CustomersViewModel
, we create the DelegateCommand
as follows:
1
|
_deleteCustomerCommand =
new
DelegateCommand(DeleteCustomer, CanDeleteCustomer);
|
We then expose the command from a property in our view model:
1
2
3
4
|
public
ICommand DeleteCustomersCommand
{
get
{
return
_deleteCustomerCommand; }
}
|
And bind to it in the view:
1
|
<
Button
Command
=
"{Binding DeleteCustomersCommand}"
>Delete</
Button
>
|
It’s as simple as that. The delegates supplied to the DelegateCommand
will be invoked at the appropriate times and our Delete button will only be enabled when a customer is selected. You can see all this and more in the download.
Incidentally, DelegateCommand
inherits from a base Command
class. That’s just to keep the code DRY with respect to other command classes I have, such as the ActiveAwareCommand
. I’ll talk about that one in the next post.
† The application in question was built before Prism shipped, elsewise we would be.
Download Command.cs
Download DelegateCommand.cs
Download DelegateCommandExample.zip