and*_*351 10 c# wpf mvvm relaycommand mvvm-light
我正在使用Nuget(4.1.23.0)上可用的当前版本的MvvmLight,并且调用RaiseCanExecuteChanged似乎在单元测试中没有做任何事情.场景非常简单,我有一个命令:
public RelayCommand FooCommand { get; private set; }
Run Code Online (Sandbox Code Playgroud)
我在视图模型构造函数中新建它并将其指向一些私有方法:
FooCommand = new RelayCommand(Foo, CanFoo);
private void Foo()
{
// do some fooing.
}
private bool CanFoo()
{
return SomeRequiredProperty != null;
}
Run Code Online (Sandbox Code Playgroud)
然后在setter中SomeRequiredProperty我调用RaiseCanExecuteChanged:
public object SomeRequiredProperty
{
get
{
return someRequiredProperty;
}
set
{
someRequiredProperty = value;
FooCommand.RaiseCanExecuteChanged();
}
}
Run Code Online (Sandbox Code Playgroud)
现在在单元测试中,我执行以下操作:
// Arrange
var canExecuteChanged = false;
viewModel.FooCommand.CanExecuteChanged += (sender, args) => canExecuteChanged = true;
// Act
viewModel.SomeRequiredProperty = new object();
// Assert
Assert.That(canExecuteChanged, Is.True);
Run Code Online (Sandbox Code Playgroud)
测试失败,因为我的事件处理程序没有触发.这是为什么?
更新:该行为确实在运行时工作.
固定!
nemesv在FooCommand.RaiseCanExecuteChanged()简单的电话中是正确的CommandManager.InvalidateRequerySuggested().
除此之外,FooCommand.CanExecuteChanged只需将处理程序转发给CommandManager.RequerySuggested事件:
public event EventHandler CanExecuteChanged
{
add
{
...
CommandManager.RequerySuggested += value;
}
...
}
Run Code Online (Sandbox Code Playgroud)
问题的原因是CommandManager类中的以下代码行:
private void RaiseRequerySuggested()
{
...
_requerySuggestedOperation = dispatcher.
BeginInvoke(
DispatcherPriority.Background,
new DispatcherOperationCallback(RaiseRequerySuggested),
null); // dispatcher is the Dispatcher for the current thread.
...
}
Run Code Online (Sandbox Code Playgroud)
此行在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;
}
}
Run Code Online (Sandbox Code Playgroud)
我的测试现在看起来像这样:
// 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);
Run Code Online (Sandbox Code Playgroud)
而且,最重要的是,它通过:)
| 归档时间: |
|
| 查看次数: |
2818 次 |
| 最近记录: |