views:

290

answers:

1

Hello!

I'm writing a WPF application using the MVVM pattern, based on the following article: WPF Apps With The Model-View-ViewModel Design Pattern

I have two buttons on my View with the buttons' "Command" property bound (with data binding) to a given instance of the RelayCommand class (see "Figure 3 The RelayCommand Class" from the article above). The RelayCommand class has support for checking whether the given command can be executed.

WPF automatically disables buttons whose command cannot be executed.

Each of my commands (in the ViewModel class) start a background operation, and the command cannot be executed again until the background operation is finished. The RelayCommand instances have information whether the background operation is still working or it is finished.

My problem is the following: after pressing the any of the buttons, the buttons automaticaly go disabled (which is OK) because the background operation started and the command cannot be executed until it is finished, but after the operation had finished, the buttons don't go enabled automatically because their command's "can be executed" predicate is not automatically reevaluated. The reevaluation can be manually triggered by having the application loose and regain focus (by pressing ALT+TAB). After doing this trick, the buttons get enabled once again.

How can I programatically reevaluate the buttons' command's "can execute" state?

+4  A: 

You can call InvalidateRequerySuggested on the CommandManager to notify that CanExecute should be re-queried:

CommandManager.InvalidateRequerySuggested();

http://msdn.microsoft.com/en-us/library/system.windows.input.commandmanager.invalidaterequerysuggested.aspx

This does depend on whether the particular ICommand implementation has properly implemented the ICommand.CanExecuteChanged pattern, so YMMV.

Update

For instance, I use Prism which has it's own base implementation ICommand: DelegatedCommand. I find that calling RaiseCanExecuteChanged(), on a DelegatedCommand in Prism work for me.

Update 2

And make sure that you are calling InvalidateRequerySuggested() on the UI thread. Use the Dispatcher if necessary to make the call.

chibacity
This is the very same thing that my first guess was, but, for some unknown reason to me, it doesn't seem to work.I'm calling this static method ("CommandManager.InvalidateRequerySuggested") every time the state of the program (like Idle, Working, PendingStop etc.) changes, it's only this state property that is used in the canExecute handlers.Still, it doesn't seem to work (though I agree that it should).BTW, go and check the ICommand implementation, it's in the article I referenced before, figure 3.
dzs
Yes it does really depend on how ICommand has been implemented. I have updated my answer detailing how I get CanExecute re-queried in Prism. I will look at the article you are following.
chibacity
Is this something possibly to do with executing InvalidateRequerySuggested() on a non-UI thread? Try using the Dispatcher to call it, so that it is called on the UI thread.
chibacity
Good call, I'm gonna try calling it with the Dispatcher.
dzs
It works through the dispatcher, thanks!
dzs