[英]MVVMLight RelayCommand.RaiseCanExecuteChanged don't raise the CanExecuteChanged event
[英]Why doesn't RelayCommand RaiseCanExecuteChanged work in a unit test?
我正在使用Nuget(4.1.23.0)上可用的當前版本的MvvmLight,並且調用RaiseCanExecuteChanged似乎在單元測試中沒有做任何事情。 場景非常簡單,我有一個命令:
public RelayCommand FooCommand { get; private set; }
我在視圖模型構造函數中新建它並將其指向一些私有方法:
FooCommand = new RelayCommand(Foo, CanFoo);
private void Foo()
{
// do some fooing.
}
private bool CanFoo()
{
return SomeRequiredProperty != null;
}
然后在SomeRequiredProperty
的setter中我調用RaiseCanExecuteChanged:
public object SomeRequiredProperty
{
get
{
return someRequiredProperty;
}
set
{
someRequiredProperty = value;
FooCommand.RaiseCanExecuteChanged();
}
}
現在在單元測試中,我執行以下操作:
// Arrange
var canExecuteChanged = false;
viewModel.FooCommand.CanExecuteChanged += (sender, args) => canExecuteChanged = true;
// Act
viewModel.SomeRequiredProperty = new object();
// Assert
Assert.That(canExecuteChanged, Is.True);
測試失敗,因為我的事件處理程序沒有觸發。 這是為什么?
更新:該行為確實在運行時工作。
固定!
nemesv是正確的,因為FooCommand.RaiseCanExecuteChanged()
只是調用CommandManager.InvalidateRequerySuggested()
。
除此之外, FooCommand.CanExecuteChanged
只是將處理程序轉發到CommandManager.RequerySuggested
事件:
public event EventHandler CanExecuteChanged
{
add
{
...
CommandManager.RequerySuggested += value;
}
...
}
問題的原因是CommandManager類中的以下代碼行:
private void RaiseRequerySuggested()
{
...
_requerySuggestedOperation = dispatcher.
BeginInvoke(
DispatcherPriority.Background,
new DispatcherOperationCallback(RaiseRequerySuggested),
null); // dispatcher is the Dispatcher for the current thread.
...
}
此行在Dispatcher工作項隊列中放置帶有DispatcherPriority Background
的工作項。 該工作項應該通知CommandManager.RequerySuggested
事件的所有處理程序。
問題是這個工作項永遠不會運行。
解決方案是強制調度程序運行工作項。
我在MVVM Foundation CodePlex頁面的討論中找到了解決方案。 我設法將代碼簡化為以下幫助程序類。
public static class DispatcherTestHelper
{
private static DispatcherOperationCallback exitFrameCallback = ExitFrame;
/// <summary>
/// Synchronously processes all work items in the current dispatcher queue.
/// </summary>
/// <param name="minimumPriority">
/// The minimum priority.
/// All work items of equal or higher priority will be processed.
/// </param>
public static void ProcessWorkItems(DispatcherPriority minimumPriority)
{
var frame = new DispatcherFrame();
// Queue a work item.
Dispatcher.CurrentDispatcher.BeginInvoke(
minimumPriority, exitFrameCallback, frame);
// Force the work item to run.
// All queued work items of equal or higher priority will be run first.
Dispatcher.PushFrame(frame);
}
private static object ExitFrame(object state)
{
var frame = (DispatcherFrame)state;
// Stops processing of work items, causing PushFrame to return.
frame.Continue = false;
return null;
}
}
我的測試現在看起來像這樣:
// 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);
而且,最重要的是,它通過:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.