Search code examples
c#.netwpfmvvmicommand

CommandManager.InvalidateRequerySuggested does not fire RequerySuggested


I'm trying to test a class that uses CommandManager.RequerySuggested and noticed that calling CommandManager.InvalidateRequerySuggested does not fire RequerySuggested from my test. Is there a reason for this and how to I resolve this issue? Does the CommandManager require some initialization?

Code to reproduce the issue:

[Test]
public void InvalidateRequerySuggested_TriggersRequerySuggested()
{
    bool triggered = false;
    CommandManager.RequerySuggested += (s, a) => triggered = true;

    CommandManager.InvalidateRequerySuggested();
    Thread.Sleep(1000); // Just to be sure

    Assert.True(triggered); // Never true
}

Solution

  • As stated on the msdn here under remarks, CommandManager.RequerySuggested only holds a weak event reference. In your unit test the lambda expression is being garbage collected.

    Try the following:

    bool triggered;
    EventHandler handler = (s, e) => triggered = true;
    CommandManager.RequerySuggested += handler;
    CommandManager.InvalidateRequerySuggested();
    GC.KeepAlive(handler);
    Assert.IsTrue(triggered);
    

    Update

    From some further investigation, I believe I have pinpointed the problem.

    CommandManager.InvalidateRequestSuggested() uses the current dispatcher to raise the event asynchronously.

    Here is a solution:

    bool triggered;
    EventHandler handler = (s, e) => triggered = true;
    CommandManager.RequerySuggested += handler;
    CommandManager.InvalidateRequerySuggested();
    
    // Ensure the invalidate is processed
    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => { }));
    
    GC.KeepAlive(handler);
    Assert.IsTrue(triggered);