我在 WPF4 项目中使用 MVVMLight,并设置了 ApplyCommand 和 UndoCommand,它们绑定到视图上的按钮。所有标准的东西,做了很多次。当用户单击按钮时,将调用 WCF 服务方法,并更新局部变量。UndoCommandCanExecute 方法使用此局部变量来确定 UndoCommand 是否可以运行。
如果我同步进行 WCF 服务调用,这可以正常工作。但是,如果我使用异步调用,则不会触发 CanExecute 方法,因此无法正确启用/禁用撤消按钮。
这是视图模型上由两个命令调用的私有方法的简化版本。在实际代码中,传入参数,在服务调用中使用。
private void CallServiceMethod() {
IsBusy = true;
Task t = new Task(() => {
Thread.Sleep(2000); // would really call a WCF service
SetUndoMessage();
IsBusy = false;
});
t.Start();
}
如前所述,为简单起见,WCF 服务调用已替换为对 Thread.Sleep 的调用。SetUndoMessage() 方法设置 UndoCommandCanExecute 方法使用的局部变量。IsBusy 是一个 bool,绑定到视图上的 Telerik 忙碌指示器,因此用户可以看到正在发生的事情。
运行此程序时,在您单击窗口上的某个位置之前,不会正确启用或禁用撤消按钮。我在所有地方都添加了 Debug.WriteLine 语句,我可以看到在任务回调结束时没有调用 UndoCommandCanExecute 方法。
我尝试在任务回调的末尾添加以下两行,但它没有帮助......
CommandManager.InvalidateRequerySuggested();
UndoCommand.RaiseCanExecuteChanged();
如果我删除 Thread.Sleep,那么它工作正常,这听起来像是延迟问题。此方法在任务结束之前结束,因此 UndoCommandCanExecute 方法不会触发。我不明白为什么当我调用它的 RaiseCanExecuteChanged 方法或 CommandManager 时它不会触发。
我尝试在启动线程后立即添加 t.Wait() ,但是直到服务调用结束后忙指示符才出现,否定了整个目的。
任何人有任何想法如何解决这个问题?我想保留异步调用,因为这样我就可以使用忙碌指示器,这是整个大型应用程序的标准配置,并且还可以向用户提供一些正在发生的事情的反馈。
顺便说一句,我一直在使用 C# 4,因此我无法使用 C# 5 的新异步功能,即使它们可以解决问题。