Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
680 views
in Technique[技术] by (71.8m points)

wpf - Weird problem where Button does not get re-enabled unless the mouse is clicked

My app is written using the MVVM pattern in WPF, and all of my Buttons use Command bindings to execute code in my model. All commands have code in CanExecute to determine the bound Button's Enabled state. The logic works perfectly, but in all cases, the GUI remains in a disabled state unless I click somewhere else in the GUI.

For example, I have a button called Discard Candy. When I click this button, it launches a process in a threadpool thread, which sets a bool property called Running to true. Since the CanExecute method for Discard Candy's command looks something like this

public bool CanExecute(object parameter)
{
  return !Running;
}

the button will be disabled once the process starts. The problem is that when the process is done, Running gets set to false, but the GUI doesn't update, i.e. Discard Candy doesn't get re-enabled.

However, if I click anywhere in the GUI, like on the window or title bar, the Discard Candy button all of a sudden gets enabled. So the logic works, but something is going on that I just don't understand. Can someone please explain this behavior to me?

EDIT -- so far, it sounds like CommandManager.InvalidateRequerySuggested hasn't helped people. I am going to give it a shot, but at the moment am a little wary of it. I did follow the recommended links, and in doing so decided to read more about the MVVM light toolkit. It sounds very nice -- has anyone here used it and been able to confirm that it does not exhibit the problem I've been seeing so far? Although I plan to try the MVVM light toolkit in the next major rev. of my application, I don't want to redo all of the commanding that I currently have in place, which is why I'll likely start with CommandManager.InvalidateRequerySuggested so we can all get another data point here regarding it's usefulness.

EDIT #2 -- very interesting, the MVVM light toolkit actually relies on CommandManager.InvalidateRequerySuggested in order to support the UI's ability to disable / re-enable commands. The author says:

"Strictly speaking, in WPF, and if your command is bound to a control that is watched by the CommandManager, you shouldn’t have to raise the CanExecuteChanged event yourself. You can let the CommandManager handle the situation. That said, external events might also change the state of the UI. Let’s imagine that the UI should be enabled from 9AM to 5PM, and then disabled for the night. The user is not triggering the UI, so the code should request (politely) that the CommandManager requeries the state of the commands. This is done by calling the method InvalidateRequerySuggested on the CommandManager. And as you guessed, the method RaiseCanExecuteChanged of the RelayCommand class does just that."

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

WPF doesn't update command bound controls unless it has a reason to. Clicking on the GUI causes WPF to refresh so the update then works.

You can manually cause a refresh of any command bound controls by calling CommandManager.InvalidateRequerySuggested.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...