Wednesday, December 08, 2010

Very Simple Example of ICommand CanExecute Method and CanExecuteChanged Event

Michael Washington said I should blog about this, so if it’s too mundane, blame him. I added some animation stuff to hopefully make it a little more interesting.
Consider a simulation where the ViewModel controls the onscreen action. On the following screen, clicking the Start Button will cause the space ship to fly around the the screen. But the Start Button should only be enabled if the ViewModel actually has access to the space ship and the Speed is valid.

The Details

ICommand  provides an interface that can easily be bound to by the View to execute code in the ViewModel. In addition to the Execute() method you might expect, it also calls for a CanExecute() method. CanExecute() returns true if Execute() can currently be ‘executed’ safely. If you bind a Button.Command property to an ICommand implementation, the Button is automatically enabled or disabled according to the value returned by CanExecute(). But CanExecute() is a method, not a property, so if conditions change so CanExecute() would return true rather than false, or vice-versa, Button must know to call CanExecute() to find the new value.

That’s where CanExecuteChanged comes in. Button, through its base class, ButtonBase, is automatically subscribed to the CanExecuteChanged event when the Button.Command property is bound to the ICommand. As you might expect, when ButtonBase catches the CanExecuteChanged Event it responds by calling the CanExecute() method and sets the Button.Enabled state accordingly. So in your code, whenever a condition or property changes that affect what CanExecute() will return, the CanExecuteChanged event should be raised.

I’ll point out here that CanStartAnimation(), which is the method that you supply when you create StartAnimationCommand , will be called by CanExecute() to determine what value to return. In this simple example, CanStartAnimation() returns true if the ViewModel has access to the spaceShip FrameworkElement. To clarify a little futher  StartAnimationCommand is an ICommand property on MainPageViewModel. Specifically it is an instance of DelegateCommand,, a class generously provided by John Papa, which of course implements ICommand. The beauty of DelegateCommand is that it lets you define the methods to be called by CanExecute() and Execute().
CanExecute() doesn’t merely return the result from CanStartAnimation(). As you can see in the DelegateCommand source for CanExecute(), it determines whether the bool from CanStartAnimation() – which it just sees as a function pointer named canExecute that accepts an object and returns the bool in question, is different from the bool it got before. If so, it raises the CanExecuteChanged event.

public class DelegateCommand : ICommand
{
   Func<object, bool> canExecute;
   Action<object> executeAction;
   bool canExecuteCache;
   public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute)
   {
       this.executeAction = executeAction;
       this.canExecute = canExecute;
   }
   #region ICommand Members
   public bool CanExecute(object parameter)
   {
       bool temp = canExecute(parameter);
       if (canExecuteCache != temp)
       {
           canExecuteCache = temp;
           if (CanExecuteChanged != null)
           {
               CanExecuteChanged(this, new EventArgs());
           }


Read more: OpenLight Blog