2013-06-27 38 views
1

我在WPF4项目中使用MVVMLight,并且已经设置了一个ApplyCommand和一个UndoCommand,它们绑定到视图上的按钮。所有标准的东西,做了很多次。当用户单击按钮时,将调用WCF服务方法,并更新局部变量。 UndoCommandCanExecute方法使用此局部变量来确定是否可以运行UndoCommand。MVVMLight命令CanExecute在异步调用后不会触发

这工作正常,如果我同步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是绑定到视图上的Telerik繁忙指示符的布尔,所以用户可以看到发生了某些事情。

运行此操作时,撤消按钮不能正确启用或禁用,直到您单击窗口上的某处。我在整个地方添加了Debug.WriteLine语句,并且可以看到在任务回调结束时未调用UndoCommandCanExecute方法。

我试图在任务回调的末尾添加以下两行,但它并没有帮助...

CommandManager.InvalidateRequerySuggested(); 
    UndoCommand.RaiseCanExecuteChanged(); 

如果我删除了Thread.Sleep,然后正常工作,这听起来就像是延迟就是问题所在。此方法在任务结束之前结束,因此UndoCommandCanExecute方法不会触发。我不明白为什么它在我调用RaiseCanExecuteChanged方法或CommandManager时不会触发。

我尝试在我启动线程后立即添加t.Wait(),但直到服务调用结束后才显示忙指示,否定了整个目的。

任何任何想法如何解决这个问题?我想保持异步调用,因为这使我可以使用忙碌指示符,这是整个大型应用程序的标准,并且还向用户提供了一些反馈,指出发生了什么。

我被卡住了使用C#4的方式,所以C#5的新异步功能对我来说不可用,即使它们能解决问题。

+0

任何人能帮助我们吗? –

回答

0

我有同样的问题,我能够以两种不同的方式纠正它,不知道哪一个是最好的。

1)在我的任务,我就把:

App.Current.Dispatcher.BeginInvoke((Action)delegate() 
        { 
         yourCommand.RaiseCanExecuteChanged(); 
        }); 

我真的不喜欢不必调用RaiseCanExecuteChanged在多个地方的想法,所以我最终使用这样的:

2)一世。我添加到构造函数中:

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,但RelayCommand代替DelegateCommand工程太