问题
Background
While looking at Josh Smith's article about CommandGroup
, I noticed that there are a number of comments on the Internet about how to implement ICommand.CanExecuteChanged
.
A similar question was posted here on StackOverflow, but
- I don't feel like there is a clear answer, and
- there is not enough room in a comment to be able to add additional context.
For reference:
- Josh Smith's original article about
CommandGroup
uses a simple .NET event - Josh Smith's
RelayCommand
uses aCommandManager
implementation ofCanExecuteChanged
- Microsoft's own
RoutedCommand
uses aCommandManager
implementation ofCanExecuteChanged
- Microsoft's own PRISM library (version: 6) also uses a simple .NET event (previous versions used weak references)
My Question
I am relatively new to WPF, and I would like to know how the CanExecuteChanged
event should have been implemented in Josh Smith's CommandGroup
to avoid any unexpected behaviors or memory leaks?
Additional Reading
Josh Smith: Aggregating WPF Commands with CommandGroup
Josh Smith: WPF apps with the MVVM design pattern
StackOverflow: Is Josh Smith's implementation of the RelayCommand flawed?
StackOverflow: comment about CanExecuteChanged
Microsoft: RoutedCommand
PRISM 6: DelegateCommandBase
回答1:
Lets say you bind a command to a button. When the button is about to be rendered, it would call CanExecute() and based on the result will render either as Enabled or Disabled. WPF automatically calls CanExecute() when "it decides", but you should never relay on this behavior.
Thus, when you implement ICommand, declare a method like UpdateCommand(), which will raise the event in question when You decide. For example, if clicking on a button starts a slow operation which should be triggered again once the previous one has finished, you should raise the event twice - once prior to starting the operation and once after it finishes.
There is no such thing as "the best way to to implement ICommand.CanExecuteChanged". Probably that was part of the reasons not to ship a default implementation of ICommand with the framework. Most MVVM framework, provide default implementations: RelayCommand, ActionCommand, ParameterCommand, AsyncCommand, etc. They just make things easier - pass a delegate and you're ready to go. The Josh Smith's article solves a different issue, a neat way to chain multiple routed command in XAML.
In general:
- Use ICommand with MVVM
- Use RoutedCommand when you are creating reusable controls and you want the command to bubble up the visual tree, so the interested ascendants can handle it
- You can use the Decorator design pattern and decorate all of you commands, so that you can add an upper layer of functionality, like commands active only for privileged users, disable all commands at once, etc. Just make sure the decorator subscribes for the actual command's CanExecuteChanged and re-fires the event on its behalf
来源:https://stackoverflow.com/questions/46475445/how-should-icommand-canexecutechanged-be-implemented