Alex Rivera | Logout

Refresh WPF Command

Asked 2009-04-23T19:06:02.390
75

Does anyone know how I can force CanExecute to get called on a custom command (Josh Smith's RelayCommand)?

Typically, CanExecute is called whenever interaction occurs on the UI. If I click something, my commands are updated.

I have a situation where the condition for CanExecute is getting turned on/off by a timer behind the scenes. Because this is not driven by user interaction, CanExecute is not called until the user interacts with the UI. The end result is that my Button remains enabled/disabled until the user clicks on it. After the click, it is updated correctly. Sometimes the Button appears enabled, but when the user clicks it changes to disabled instead of firing.

How can I force an update in code when the timer changes the property that affects CanExecute? I tried firing PropertyChanged (INotifyPropertyChanged) on the property that affects CanExecute, but that did not help.

Example XAML:

<Button Content="Button" Command="{Binding Cmd}"/>

Example code behind:

private ICommand m_cmd;
public ICommand Cmd
{
    if (m_cmd == null)
        m_cmd = new RelayCommand(
            (param) => Process(),
            (param) => EnableButton);

    return m_cmd;
}

// Gets updated from a timer (not direct user interaction)
public bool EnableButton { get; set; }
Edit
Report

2 Answers

105

Calling System.Windows.Input.CommandManager.InvalidateRequerySuggested() forces the CommandManager to raise the RequerySuggested event.

Remarks: The CommandManager only pays attention to certain conditions in determining when the command target has changed, such as change in keyboard focus. In situations where the CommandManager does not sufficiently determine a change in conditions that cause a command to not be able to execute, InvalidateRequerySuggested can be called to force the CommandManager to raise the RequerySuggested event.

answered 2009-04-23T19:08:44.070
4

Thanks guys for the tips. Here's a bit of code on how to marshal that call from a BG thread to the UI thread:

private SynchronizationContext syncCtx; // member variable

In the constructor:

syncCtx = SynchronizationContext.Current;

On the background thread, to trigger the requery:

syncCtx.Post( delegate { CommandManager.InvalidateRequerySuggested(); }, null );

Hope that helps.

-- Michael

answered 2011-03-03T19:45:57.393

Your Answer