Weak references & the Prism DelegateCommand

I’ve recently been getting to know WPF rather better than I’d like.

We make a lot of use of the Prism DelegateCommand. One such command had a handler attached to it’s CanExecuteChanged event:

var command = new DelegateCommand(Execute, CanExecute);
command.CanExecuteChanged += OnCommandCanExecuteChanged;

When we asked the command to re-evaluate whether it could execute:

command.RaiseCanExecuteChanged();

Then OnCommandCanExecuteChanged should have been called.

Sometimes it was, sometimes it wasn’t. Or, more accurately, it was at first and then later it wasn’t.

A bit of digging into the sauce of the DelegateCommand (thanks R#!), confirmed the suspicion:

    public event EventHandler CanExecuteChanged
    {
      add
      {
        WeakEventHandlerManager.AddWeakReferenceHandler(ref this._canExecuteChangedHandlers, value, 2);
      }
      remove
      {
        WeakEventHandlerManager.RemoveWeakReferenceHandler(this._canExecuteChangedHandlers, value);
      }
    }

The command holds a weak reference to the event handler. And, if that’s the only reference, then it’s just a matter of time before it gets GCed; and your handler will no longer be called.

After some hair pulling, and a few false starts, it turned out the solution was to keep our own reference to the actual event handler. Makes perfect sense now, but it certainly wasn’t obvious at first!

public class CommandHolder
{
    private readonly EventHandler eventHandler;

    public ICommand Command { get; private set; }

    public CommandHolder()
    {
        Command = new DelegateCommand(Execute, CanExecute);
        eventHandler = OnCanExecuteChanged;
        Command.CanExecuteChanged += eventHandler;
    }

    private void Execute() { }

    private bool CanExecute() { return true; }

    private void OnCanExecuteChanged(object sender, EventArgs e) { }
}

I assume the reason for the weak references is to try & avoid memory leaks caused by failing to unbind event handlers. Unfortunately, it can leave you with a tricky bug to investigate.

5 thoughts on “Weak references & the Prism DelegateCommand

  1. Martin June 12, 2013 / 9:26 am

    Simplest explanation of this problem and its solution (I encountered it quite often during unit testing). Thank you!

    • Rob G June 28, 2013 / 9:46 am

      To clarify, the pattern used here is an alternative solution to the Weak Event Pattern. It may have been better to use the Weak Event Pattern, as its part of WPF itself and documented properly.

  2. Dave February 11, 2022 / 3:46 pm

    I just wanted to say a huge thank you for this. I also ran into this problem with writing unit tests. I’ve implemented a CanExecuteChangedEventChecker so that RaiseCanExecuteChanged can be “arranged” during tests, but I could not work out why just occasionally the event didn’t get raised. I spent days on it, and finally worked out it had to do with weak referencing, and then I found this article. I wonder if it is just a problem with Prism DelegateCommand or with other implementations of ICommand too. Anyway, thanks a million.

    • Graham Hay February 12, 2022 / 12:05 pm

      I have zero recollection of writing this, but I imagine it cost me a few days too :)

Leave a comment