Fixed!
nemesv was right that FooCommand.RaiseCanExecuteChanged() just calls CommandManager.InvalidateRequerySuggested() .
In addition to this, FooCommand.CanExecuteChanged simply forwards the handler to the CommandManager.RequerySuggested event:
public event EventHandler CanExecuteChanged { add { ... CommandManager.RequerySuggested += value; } ... }
The cause of the problem was the following line of code in the CommandManager class:
private void RaiseRequerySuggested() { ... _requerySuggestedOperation = dispatcher. BeginInvoke( DispatcherPriority.Background, new DispatcherOperationCallback(RaiseRequerySuggested), null);
This line places the work item with DispatcherPriority Background on Dispatcher . The work item is supposed to notify all handlers of the CommandManager.RequerySuggested event.
The problem is that this work item never starts.
The solution is to force the dispatcher to run the work item.
I found a solution to this discussion on the MVVM Foundation CodePlex page. I was able to simplify the code a bit in the following helper class.
public static class DispatcherTestHelper { private static DispatcherOperationCallback exitFrameCallback = ExitFrame;
My test now looks like this:
// Arrange var canExecuteChanged = false; viewModel.FooCommand.CanExecuteChanged += (sender, args) => canExecuteChanged = true; // Act viewModel.SomeRequiredProperty = new object(); DispatcherTestHelper.ProcessWorkItems(DispatcherPriority.Background); // Assert Assert.That(canExecuteChanged, Is.True);
And, most importantly, it passes :)
andrej351
source share