Endjin - Home

Silverlight CommandManager

by Matthew Adams

As WPF and Silverlight developers, one of the most powerful tools in our utility belt is command binding.

A quick dive into WPF

WPF has a fairly full-featured command infrastructure, including a rather useful type called the CommandManager, which ensures that our controls are correctly enabled and disabled as the Command to which they are bound changes the answer it gives to the question CanExecute(…).

The WPF RoutedCommand class integrates with CommandManager by implementing its CanExecuteChanged event over the CommandManager’s own RequerySuggested event , like this:

public event EventHandler CanExecuteChanged
{
    add
    {
        CommandManager.RequerySuggested += value;
    }
    remove
    {
        CommandManager.RequerySuggested -= value;
    }
}

This has the effect of raising CanExecuteChanged on our command whenever the CommandManager.RequerySuggested is raised, thus notifying anyone who is bound to that command that they should call CanExecute() again and update their state accordingly.

This leads to the question, when is RequerySuggested raised?

The first, and perhaps most obvious case is when you explicitly call the static method CommandManager.InvalidateRequerySuggested(). You might do this at the end of a complex internal state change to ensure that the UI correctly reflects the result of that change.

You can see this happening in some of the controls that are part of the framework itself. DataGrid explicitly calls InvalidateRequerySuggested() when it changes its internal state – at the end of the AddNewItem() method for example.

If we had to do this manually for every possible change of state, this would get very boring, very quickly. Fortunately, the WPF framework has another trick up its sleeve. In an interactive application, most (though by no means all) application state is mutated by some kind of user-originated input; if we raise the requery event whenever the user clicks something, or types something, or touches something, then we’ll catch most of the cases we need. To do this, WPF uses a class called the CommandDevice.

CommandDevice adds a handler for the PostProcessInput event which is exposed by a class called the InputManager. The InputManager looks after all of the keyboard, mouse, stylus and touch devices for WPF, and raises this event for us when input occurs. The CommandDevice responds to this event (amongst other ways) by calling InvalidateRequerySuggested()– thus updating the state of our command bindings whenever the user manipulates the UI, without requiring our manual intervention.

This doesn’t just work for RoutedCommand, of course. To augment the view-oriented RoutedCommand class, most developers using the MVVM pattern take advantage of something like the RelayCommand originally popularized by Josh Smith in his MSDN magazine article. This is allows us to define commands that delegate to methods on our view model, rather that the view, with separation of concerns and testability in mind.

Here’s endjin’s implementation of that class (inherited and tweaked down a long path from Josh Smith via Laurent Bugnion).

namespace Endjin.Commands
{
    using System;
    using System.Diagnostics;
    using System.Windows.Input;
    /// <summary>
    /// A command whose purpose is to relay its functionality to
    ///   other objects by invoking delegates.
    ///   The default return value for the CanExecute method
    ///   is 'true'.
    ///   This class does not allow you to accept command
    ///   parameters in the Execute and CanExecute callback
    ///    methods.
    /// </summary>
    public class RelayCommand : ICommand
    {
        private readonly Action execute;
        private readonly Func<bool> canExecute;
        /// <summary>
        /// Initializes a new instance of the RelayCommand class.
        /// </summary>
        /// <param name="execute">
        /// The execution logic.
        /// </param>
        /// <param name="canExecute">
        /// The execution status logic.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if the execute argument is null.
        /// </exception>
        public RelayCommand(
            Action execute,
            Func<bool> canExecute = null)
        {
            if (execute == null)
            {
                throw new ArgumentNullException("execute");
            }
            this.execute = execute;
            this.canExecute = canExecute;
        }

        /// <summary>
        ///   Raised when changes occur that affect
        ///   whether the command should execute.
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (this.canExecute != null)
                {
                    CommandManager.RequerySuggested += value;
                }
            }
            remove
            {
                if (this.canExecute != null)
                {
                    CommandManager.RequerySuggested -= value;
                }
            }
        }

        /// <summary>
        /// Raises the <see cref="CanExecuteChanged"/> event.
        /// </summary>
        public void RaiseCanExecuteChanged()
        {
            CommandManager.InvalidateRequerySuggested();
        }

        /// <summary>
        /// Defines the method that determines whether the
        /// command can execute in its current state.
        /// </summary>
        /// <param name="parameter">
        /// This parameter will always be ignored.
        /// </param>
        /// <returns>
        /// true if this command can be executed; otherwise,
        /// false.
        /// </returns>
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return this.canExecute == null ? true
                                            : this.canExecute();
        }
        /// <summary>
        /// Defines the method to be called when the
        /// command is invoked.
        /// </summary>
        /// <param name="parameter">
        /// This parameter will always be ignored.
        /// </param>
        public void Execute(object parameter)
        {
            this.execute();
        }
    }
}

(There is a generic version of this too that you’ll find in the sample code attached to this post.)

Notice how we’re implementing the CanExecuteChanged event handler in exactly the same way as the RoutedCommand.

Silverlight

Things are a bit different in Silverlight. Although ICommand exists, none of the rest of the infrastructure is present. Specifically, you have to build your own command implementation (the RelayCommand pattern is all we really need for our MVVM apps); but what to do about the lack of CommandManager?

Traditionally, the approach people have taken is to implement and manually raise the CanExecuteChanged property on your RelayCommand instances. This is exactly the tedious and error-prone technique I mentioned earlier. A better approach might be to implement our own CommandManager for Silverlight.

We’ve got two goals in mind:

1) Automatic raising of CanExecuteChanged when we think we might need it

2) Centralizing InvalidateRequerySuggested() rather than forcing you to handle it for each and every command.

Clearly, we can achieve the second goal, just by creating a CommandManager class with the necessary event and method, and implementing our RelayCommand over it in exactly the same way as the WPF implementation (in fact, you can just share the RelayCommand source code unchanged between the two platforms if you do this).

But what about the first goal?

Sadly, we can’t integrate into the Silverlight input food-chain in the same way as the WPF implementation does. What other integration points do we have? Probably the best place we can get some automation is in our INotifyPropertyChanged implementation.

INotifyPropertyChanged recap

If you’re reading this, you probably know all about INotifyPropertyChanged. It is the interface that we implement on our view model classes to integrate with the data binding infrastructure in WPF and Silverlight. If not, then this MSDN how-to can get you started.

We can leverage the fact that whenever any property change occurs in which the UI might be interested, the OnPropertyChanged() method will be called; so we call InvalidateRequerySuggested() from in there.

Like this:

private void OnPropertyChangedCore(string propertyName)
{
    if (this.PropertyChanged != null)
    {
        PropertyChangedEventArgs eventArgs =
            LookupEventArgs(propertyName);
        this.PropertyChanged(this, eventArgs);
    }
#if SILVERLIGHT
    CommandManager.InvalidateRequerySuggested();
#endif
}

Isn’t that going to be a massive performance problem? Every single property change kicking off a UI refresh?

Well – it might have been, but we haven’t looked at the implementation of CommandManager.InvalidateRequerySuggested() yet. Here it is:

public static void InvalidateRequerySuggested()
{
    Current.RaiseCanExecuteChanged();
}

Current is our internal singleton for the CommandManager (and is an instance of the CommandManager itself). Let’s take a look at that event-raising method.

private void RaiseCanExecuteChanged()
{
    if (this.hasCanExecuteQueued)
    {
        return;
    }
    this.hasCanExecuteQueued = true;

    DispatcherHelper.UIDispatcher.BeginInvoke(
        () =>
        {
            CallWeakReferenceHandlers(eventHandlers);
                 this.hasCanExecuteQueued = false;
        });
}

The key pattern here is that we use the DispatcherHelper (a class that wraps the UI Dispatcher)  to asynchronously invoke our method that calls all the event handlers (which are managed as weak references to avoid a leak).

This doesn’t mean that we’re calling the handlers from a background thread – nothing “concurrent” is happening. What actually happens is that we’re waiting for our event handling to unwind itself back to the idle state and then call the handlers. This all happens ‘in order’ – you’re just deferring the bit of code that calls the handlers until after we’ve finished dealing with the current user input. If you hammer away at the keyboard or mouse, this takes priority, and we “lose” a bunch of changes of state, finally catching up with ourselves at the end.

This is particularly powerful if there are lots of knock-on changes from one property change – the UI doesn’t flicker enabled/disabled/enabled/disabled if it is temporarily unstable before regaining its equilibrium.

Here’s some sample code that illustrates this in action.


Note that this is all internal detail, and is subject to change, but is believed to be correct at the time of writing with .NET 4.0.

Actually, this is not strictly true. In WPF we could specify that we wanted to asynchronously invoke that method at idle priority. In Silverlight, we can’t be so specific, but the semantics are sufficiently similar for this to work.

Matthew Adams on Twitter

About the author

Matthew was CTO of a venture-backed technology start-up in the UK & US for 10 years, and is now a Founder of Endjin Ltd, which provides technology strategy, experience and development services to its clients who are seeking to take advantage of Microsoft Azure and the Cloud. You can follow Matthew on twitter.