views:

1706

answers:

3

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; }
+15  A: 

CommandManager.InvalidateRequerySuggested()

HTH, Kent

Kent Boogaart
Do you suggest calling this from a ViewModel class?
Josh G
Not necessarily, as that may make your class hard to test. Try it, and move it into a service if necessary. Another option is to add a method to RelayCommand that allows you to raise CanExecuteChanged just for that command (CommandManager.InvalidRequerySuggested invalidates all commands, which is somewhat of an overkill).
Kent Boogaart
Interesting... It works, but it has to be called on the UI thread. I'm not surprised.
Josh G
So I have to fire CanExecuteChanged for the event to get evaluated?
Josh G
OK, it clicks now. Thanks, Kent.
Josh G
...Clicks... no pun intended! :-)
Josh G
Heh, heh. Was thinking about my previous comment about raising CanExecuteChanged for that command only. That will only be possible if a separate list of event handlers is maintained. I'm still pondering whether that's a good idea or not.
Kent Boogaart
Any more thoughts here, Kent?
Tom
@Tom: seems to me it should work fine. Basically you would have an EventHandlerList that you maintain in conjunction with adding handlers to CommandManager.CanExecuteChanged. Then you have a method to raise the CanExecuteChanged for that command only by using the EventHandlerList. In theory it should perform better, but I haven't tried it myself, and there's a little bit of overhead by managing the two lists.
Kent Boogaart
+3  A: 

I was aware of CommandManager.InvalidateRequerySuggested() a long time ago, and use it, but it wasn't working for me sometimes. I finally figured out why this was the case! Even though it doesn't throw like some other actions, you HAVE to call it on the main thread.

Calling it on a background thread will appear to work, but sometimes leave the UI disabled. I really hope this helps somebody, and saves them the hours I just wasted.

SilverSideDown
A: 

It did.. Many thanks.

Tobias Punke
Please post ANSWERS that are pertaining to the question. Add COMMENTS to the relevant question/answer you are responding to, or EDIT your original post. This is not a forum. Thanks!
Josh G