WPF Commanding – When do Commands re-evaluate their CanExecute method?

I had been merrily using WPF’s built-in support for the Command Pattern for ages (see Commanding Overview, MSDN Docs, and article on implementing the command pattern in WPF, Jeff Druyt)… when suddenly it occured to me that I had no idea what triggered WPF to determine whether or not a command can be executed.

Let me explain by reduction to an absurd example:

Say I have a command that can only execute when

DateTime.Now.Second % 2 == 0.

I construct this command by home-brewing a static RoutedCommand instance:

public static class Commands

{

public static RoutedCommand MyCommand { get { return m_MyCommand; } }

private static RoutedCommand m_MyCommand = new RoutedCommand

(

“Execute My Command”,

typeof(Commands),

new InputGestureCollection()

{

new KeyGesture(Key.C, ModifierKeys.Alt)

}

);

}

And then I add a Command Binding for that command to my Window, and assign the command to a Button:

<Window x:Class=”TestCommands.Window1″…>
<Window.CommandBindings>
<CommandBinding
Command=”{x:Static local:Commands.MyCommand}”
Executed=”MyCommandExecuted”
CanExecute=”MyCommandCanExecute”
/>
</Window.CommandBindings>

<Button Width=”200″ Height=”200″
Command=”{x:Static local:Commands.MyCommand}”
Content=”{Binding Path=IsEnabled}”
/>

</Window>

By nature of WPF’s awesomeness and WPF Commanding in general, the above Button’s IsEnabled property should automatically be set to true or false based on whether or not the command can or can’t be executed.

Speaking of which, let’s set up my Command’s absurd logic in the CodeBehind by implementing its Execute and CanExecute event handlers:

private void MyCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)

{

DateTime now = DateTime.Now;

if (CanExecuteOutput != null)

{

CanExecuteOutput.Text = “MyCommand CanExecute determined at “ +

now.ToLongTimeString() + ” (and “ + now.Millisecond + “ms)”;

}

e.CanExecute = DateTime.Now.Second % 2 == 0;

}

private void MyCommandExecuted(object sender, ExecutedRoutedEventArgs e)

{

TextOutput.Text = “MyCommand executed at “ + DateTime.Now.ToLongTimeString();

}

So, my example is absurd but I bet you see my point by now: WPF is meant to automatically set the IsEnabled Property on that button to true or false, based on the results of the CanExecute method. But in this case, the results of CanExecute are a function only of time, and thus change repeatedly and independently of “obvious” application events. So… how does the Commanding system know when to query CanExecute and consequently enable/disable the button once a second?

In this case, without further intervention, it doesn’t. It seems that when events are raised on the Window (a mouse button click, etc.), CanExecute is re-evaluated. (I don’t know the details and wish I did.)  But, without further programmatic or user intervention, the button will not automatically change its IsEnabled state once a second.

This led me back to the MSDN docs, where I discovered the aptly-named InvalidateRequerySuggested event. To coerce – er, suggest – that WPF should query CanExecute, I set up the following DispatcherTimer:

m_DispatcherTimer = new DispatcherTimer()

{

Interval = TimeSpan.FromSeconds(0.25),

IsEnabled = true

};

m_DispatcherTimer.Tick += delegate

{

CommandManager.InvalidateRequerySuggested();

};

Now, the IsEnabled property of the Button blinks on and off as the Command’s ability to be executed changes with the passing seconds.

Only then did I discover there’s an MSDN Docs sample called “Disable Command Source Via Dispatcher Timer Sample” which is remarkably similar.

There you have it. Now go forth and command WPF’s Commanding. I’m sure you can all execute on that request <g>

P.S. Code for this sample is here.

P.P.S. What are folks using for pasting XAML and C# code into their blogs? This entry is looking a little rough…

20 comments

  1. This doesn’t work when used with a built in command like ApplicationCommands.Print, any idea why?

    Kind regards,

    Daniel

  2. InvalidateRequerySuggested() was just what I was looking for, thanks for sharing!

  3. thanks dude, exactly what I needed. Seems like the whole command architecture is really only worth it at a certain level of complexity of your application. otherwise you’d do the same thing old school with less lines of code.

  4. Very helpfull :-)
    Could not imagine how to get my button to be enabled after a search, before to user clicked in the form. The sentence “CommandManager.InvalidateRequerySuggested();” saved my day.

  5. Thanks a lot for this good article!
    But remember that using a DispatchTimer might cause a memory leak! If you have many forms and each time the user switches to another form a new one is created, then with dispatch timer a memory leak is created.
    Do not forget to deregister the timer when the form is closed.

  6. It should be noted that InvalidateRequerySuggested() must be called from the UI thread or it will do nothing.

Comments are closed.