Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should `ICommand.CanExecuteChanged` be implemented? [closed]

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

  1. I don't feel like there is a clear answer, and
  2. there is not enough room in a comment to be able to add additional context.

For reference:

  1. Josh Smith's original article about CommandGroup uses a simple .NET event
  2. Josh Smith's RelayCommand uses a CommandManager implementation of CanExecuteChanged
  3. Microsoft's own RoutedCommand uses a CommandManager implementation of CanExecuteChanged
  4. 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

like image 712
Pressacco Avatar asked Nov 07 '22 16:11

Pressacco


1 Answers

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:

  1. Use ICommand with MVVM
  2. 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
  3. 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
like image 81
shadow32 Avatar answered Nov 15 '22 13:11

shadow32