2017-04-13 259 views
2

我遇到了一些與任務和異步/等待關鍵字混淆。我知道你不應該混用異步和阻止代碼。或者至少我對混合它們的解釋是:等待/異步任務不等待

不要調用阻塞來自非異步方法的API。所以這是我的問題。

我想等待一個方法,然後相應地更新用戶界面。問題在於等待異步方法()調用的唯一方法是從async方法和async方法中調用。

下面是一個例子:

private RelayCommand<Options> _executeCommand; 

public RelayCommand<Options> ExecuteCommand 
{ 
    get 
    {     
     return _executeCommand ?? (_executeCommand = new RelayCommand<Options>(async (options) => 
     { 
      Completed = false;      

      var cancellationTokenSource = new CancellationTokenSource(); 

      await RunValidation(options, cancellationTokenSource.Token); 

      Completed = true; 

     })); 
    } 
} 

此代碼正常運行的方法和等待。問題出在我回來的時候。出於某種原因,設置完成標誌時,取決於此標誌的按鈕不會切換。如果我評論等待代碼,那麼按鈕將正確切換。所以,假設我沒有返回UI線程上,所以我嘗試使用此代碼來代替:

private RelayCommand<Options> _executeCommand; 

public RelayCommand<Options> ExecuteCommand 
{ 
    get 
    {     
     return _executeCommand ?? (_executeCommand = new RelayCommand<Options>(async (options) => 
     { 
      Completed = false;      

      var cancellationTokenSource = new CancellationTokenSource();                 

      var context = TaskScheduler.FromCurrentSynchronizationContext(); 

      await RunValidation(options, cancellationTokenSource.Token).ContinueWith(t => Completed = true, context); 

      //Completed = true; 

     })); 
    } 
} 

這裏是RunValidation()方法:

private async Task RunValidation(Options options, CancellationToken token) 
{    
    await _someService.SomAsyncMethod(options, token)); 
} 

如果你注意到,在ExecuteCommand具有異步在傳遞給命令的(選項)參數之前的關鍵字。如果我刪除了異步關鍵字,那麼我必須修改對RunValidation()方法的調用。我仍然需要它等待,所以這就是我所做的:

private RelayCommand<Options> _executeCommand; 

public RelayCommand<Options> ExecuteCommand 
{ 
    get 
    {     
     return _executeCommand ?? (_executeCommand = new RelayCommand<Options>((options) => 
     { 
      Completed = false;      

      var context = TaskScheduler.FromCurrentSynchronizationContext(); 

      var cancellationTokenSource = new CancellationTokenSource(); 

      Task.Run(async() => await RunValidation(options, cancellationTokenSource.Token)); 

      Completed = true; 

     })); 
    } 
} 

此代碼的問題是它不會等待。所以我很茫然。

任何人都可以在這裏爲我闡明一些東西。我已經花了兩天多的時間,而我仍然在這裏。

感謝, 添

這裏是綁定命令按鈕。

private readonly Independent<bool> _completed = new Independent<bool>(true); 

public bool Completed 
{ 
    get { return _completed; } 
    set { _completed.Value = value; } 
} 

private ICommand _doneCommand; 

public ICommand DoneCommand 
{ 
    get 
    { 
     return _doneCommand ?? (_doneCommand = MakeCommand.When(() => Completed).Do(() => 
     { 
      DoSomething(); 
     })); 
    } 
} 

private ICommand _cancelCommand; 

public ICommand CancelCommand 
{ 
    get 
    { 
     return _cancelCommand ?? 
       (_cancelCommand = MakeCommand.When(() => !Completed).Do(() => DoSomthingElse())); 
    } 
} 

我使用來自Michael Perry的UpdateControls庫中的MakeCommand對象。它們包含依賴性跟蹤,在完成屬性更改時引發CanExecuteChange事件。

+2

第一個代碼塊是正確的。這些按鈕如何綁定到完成標誌?它是否可觀察? – Jason

+0

由於您的問題是由於通知丟失,因爲你正在使用應提高您通知您一個圖書館,我建議你提出問題與UpdateControls庫。 –

+0

所以我不瘋狂,從事物的外觀,我正確地做事情? – user953710

回答

0

你的第一個代碼是正確的。很有可能你的Completed屬性有錯誤的實現。您的視圖模型對象應該實現INotifyPropertyChanged。最簡單的方法是使用提供功能的基類。 ReactiveUI是我一直使用的nuget包。使用非常簡單

public class MyObject : ReactiveObject { 

    private bool _Completed; 
    public bool Completed { 
     get => _Completed; 
     set => this.RaiseAndSetIfChanged(ref _Completed, value); 
    } 

} 

這將確保在屬性發生更改時向用戶界面引發通知。

如果你想讓它更神奇,你可以使用ReactiveUI.Fody,然後你的代碼將減少

public class MyObject : ReactiveObject { 

    [Reactive] 
    public bool Completed { get; set;} 

} 
0

所以這個問題,其實是第三方庫。我使用它來爲2個按鈕提供依賴關係跟蹤。所以當完整的標誌改變後,它爲兩個按鈕提出了CanExecuteChange事件,而我沒有寫代碼去做。不幸的是,在引入異步/等待呼叫後,它停止工作。我用RelayCommands替換了2個MakeCommands,並且自己提出了事件並且一切正常。

所以感謝大家您的答覆。

Tim