An ICommand with IsEnabled
ICommand is a simple interface with three members – Execute, CanExecute, and CanExecuteChanged (more on those here). You can write your own implementations of that interface, one for each command, but that gets a bit heavyweight. So there are several implementations of ICommand that are pluggable and re-usable, like DelegateCommand, RelayCommand, and RoutedCommand.
One tricky part of implementing ICommand is the CanExecuteChanged event, because you have to know when to raise it. (The easy alternative is to raise it whenever the CommandManager.RequerySuggested event is raised, but you need to use that with caution, because it can happen frequently and get expensive.)
Really, though, CanExecute and CanExecuteChanged look like a typical Foo/FooChanged property/event pair that we use in data binding. The reason that CanExecute isn’t actually a property, though, is that it takes an optional parameter. But if you’re not using that parameter, a property would work just as well.
So I’ve been playing with an ICommand implementation that takes a delegate for the Execute method (just like DelegateCommand and RelayCommand), but also has an IsEnabled property that wraps CanExecute/CanExecuteChanged. And since it’s all a DependencyObject, you can put a binding on IsEnabled.
I wasn’t sure what to call it though. The key is that it has an IsEnabled property, but DelegateCommandWithIsEnabled didn’t sound good. And it turns out that Enabled-able isn’t a word. The closest thing I could come up with that had “able” in it was AbilityCommand. Good enough for a blog post.
Anyway, here’s what the public members look like:
public class AbilityCommand : DependencyObject, ICommand
{
public AbilityCommand(
Action<object> executeDelegate,
Binding isEnabledBinding );
public AbilityCommand( Action<object> executeDelegate )
: this( executeDelegate, null ) { }
public bool IsEnabled {get; set; }
public static readonly DependencyProperty IsEnabledProperty ...;
}
Note that you can set IsEnabled however you want, including with a binding, and in fact the constructor lets you pass in the Binding to use. AbilityCommand’s ICommand.CanExecute simply returns IsEnabled. And any time IsEnabled’s value changes, AbilityCommand raises ICommand.CanExecuteChanged.
And here it is in practice. In this snippet, the (View)Model object is the first page of a wizard-type view (with a “Next” button on it). The SubmitCommand property binds the command’s IsEnabled to the object’s IsValid property:
public class FirstPage : INotifyPropertyChanged
{
public FirstPage()
{
SubmitCommand = new AbilityCommand(
(x) => OnSubmit(),
new Binding("IsValid") { Source=this } );
}
public ICommand SubmitCommand { get; private set; }
private void OnSubmit()
{
// ...
}
// INotifyPropertyChanged fires for this IsValid property if
// either the "FirstProperty" or "SecondProperty" property is updated
public bool IsValid
{
get
{
return !String.IsNullOrEmpty(FirstProperty)
&& !String.IsNullOrEmpty(SecondProperty);
}
}
And finally, here’s the whole AbilityCommand:
public class AbilityCommand : DependencyObject, ICommand
{
Action<object> _executeDelegate;
public AbilityCommand( Action<object> executeDelegate )
: this( executeDelegate, null ) { }
public AbilityCommand(
Action<object> executeDelegate,
Binding isEnabledBinding )
{
_executeDelegate = executeDelegate;
if( isEnabledBinding != null )
BindingOperations.SetBinding(this, IsEnabledProperty, isEnabledBinding);
}
void ICommand.Execute(object parameter)
{
_executeDelegate(parameter);
}
bool ICommand.CanExecute(object parameter)
{
return IsEnabled;
}
public event EventHandler CanExecuteChanged;
private void RaiseCanExecuteChanged()
{
if( CanExecuteChanged != null )
CanExecuteChanged( this, new EventArgs() );
}
public bool IsEnabled
{
get { return (bool)GetValue(IsEnabledProperty); }
set { SetValue(IsEnabledProperty, value); }
}
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.Register("IsEnabled", typeof(bool), typeof(AbilityCommand),
new PropertyMetadata(OnIsEnabledChanged));
static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
{
(d as AbilityCommand).RaiseCanExecuteChanged();
}
}
Comments
Anonymous
March 23, 2009
PingBack from http://blog.a-foton.ru/index.php/2009/03/24/an-icommand-with-isenabled/Anonymous
March 24, 2009
Thank you for submitting this cool story - Trackback from DotNetShoutoutAnonymous
March 24, 2009
Exactly what I was looking for. Binding makes the IsEnabled a lot cleaner than sprinkling the VM with RequerySuggested calls.Anonymous
March 25, 2009
You've been kicked (a good thing) - Trackback from DotNetKicks.comAnonymous
September 27, 2012
Good one Mike.