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的新异步功能对我来说是不可用的,即使它们可以解决问题。

MVVMLight命令CanExecute在异步调用后未激发

我有同样的问题,我可以用两种不同的方法来纠正,不确定哪种是"最好的"。

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。