2
Vote

CommandReference does not hold strong reference to its handler for ICommand.CanExecuteChanged

description

Pasting from my answer on StackOverflow [*] for a description of what looks like a bug and a proposed fix (the bug did cause commanding in my application to not work and the fix did fix it). Thank you for taking a look.
 
It follows from these two points:
 
  1. It is recommended that the implementers of ICommand.CanExecuteChanged hold only weak references to the handlers (see this answer).
  2. Consumers of ICommand.CanExecuteChanged should expect (1) and hence should hold strong references to the handlers they register with ICommand.CanExecuteChanged
     
    The common implementations of RelayCommand and DelegateCommand abide by (1). The CommandReference implementation doesn't abide by (2) when it subscribes to newCommand.CanExecuteChanged. So the handler object is collected and after that CommandReference no longer gets any notifications that it was counting on.
     
    The fix is to hold a strong ref to the handler in CommandReference:
     
    private EventHandler _commandCanExecuteChangedHandler;
    public event EventHandler CanExecuteChanged;
     
    ...
    if (oldCommand != null)
    {
    oldCommand.CanExecuteChanged -= commandReference._commandCanExecuteChangedHandler;
    }
    if (newCommand != null)
    {
    commandReference._commandCanExecuteChangedHandler = commandReference.Command_CanExecuteChanged;
    newCommand.CanExecuteChanged += commandReference._commandCanExecuteChangedHandler;
    }
    ...
     
    private void Command_CanExecuteChanged(object sender, EventArgs e)
    {
    if (CanExecuteChanged != null)
        CanExecuteChanged(this, e);
    }
     
    [*] http://stackoverflow.com/a/10924171/435522

comments