2013-06-27 40 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工程太