MVVMLight命令CanExecute在异步调用后未激发
本文关键字:调用 异步 命令 CanExecute MVVMLight | 更新日期: 2023-09-27 18:20:06
我在WPF4项目中使用MVVMLight,并设置了ApplyCommand和UndoCommand,它们绑定到视图上的按钮。所有标准的东西,做了很多次。当用户单击按钮时,将调用WCF服务方法,并更新本地变量。UndoCommandCanExecute方法使用此局部变量来确定是否可以运行UndoCommand。
如果我同步地调用WCF服务,这就可以正常工作。但是,如果我使用异步调用,CanExecute方法不会被激发,因此undo按钮没有正确启用/禁用。
以下是视图模型上的私有方法的简化版本,该方法由两个命令调用。在实际代码中,参数被传入,这些参数在服务调用中使用。
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是一个绑定到视图上Telerik繁忙指示器的bool,因此用户可以看到正在发生的事情。
运行此操作时,在单击窗口上的某个位置之前,撤消按钮不会正确启用或禁用。我到处添加了Debug.WriteLine语句,可以看到当任务回调结束时,UndoCommandCanExecute方法没有被调用。
我试着在任务回调的末尾添加以下两行,但没有帮助。。。
CommandManager.InvalidateRequerySuggested();
UndoCommand.RaiseCanExecuteChanged();
如果我删除Thread.Sleep,那么它工作得很好,听起来问题出在延迟上。此方法将在任务结束之前结束,因此UndoCommandCanExecute方法不会启动。我不明白为什么当我调用它的RaiseCanExecuteChanged方法或CommandManager时,它不激发。
我试着在启动线程后立即添加t.Wait(),但直到服务调用结束后,繁忙指示器才显示出来,否定了整个目的。
有人知道怎么解决这个问题吗?我想保留异步调用,因为这允许我使用繁忙指示器,这在整个大型应用程序中是标准的,还可以向用户提供一些正在发生的事情的反馈。
顺便说一句,我一直在使用C#4,所以C#5的新异步功能对我来说是不可用的,即使它们可以解决问题。
我有同样的问题,我可以用两种不同的方法来纠正,不确定哪种是"最好的"。
1) 在我的任务中,我放了:
App.Current.Dispatcher.BeginInvoke((Action)delegate()
{
yourCommand.RaiseCanExecuteChanged();
});
我真的不喜欢必须在多个地方调用RaiseCanExecuteChanged的想法,所以我最终使用了这个:
2) i.我添加到构造函数:
this.PropertyChanged+=my_PropertyChanged;
ii。
private void me_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "whateverPropertyNamethatcontrolsit":
((RelayCommand)FirstCommand).RaiseCanExecuteChanged();
break;
}
}
iii。任务内部:
App.Current.Dispatcher.BeginInvoke((Action)delegate()
{
whateverProperty=something;
});
注意,我将MVVMLight与RelayCommand一起使用,但DelegateCommand而不是RelayCommand。