2014-03-29 231 views
2
public async override void InitData() 
    { 
     _domainModel = new DomainModel() 

     ProgressIndicatorViewModel.Start(); 
     _State = Getstate(); 
     await _domainModel.Load(_State, ProgressIndicatorViewModel); //returns a task 
     ImageSelectionViewModel.UpdateState(_State); //returns void not a task! 
     ProgressIndicatorViewModel.Stop(); 

     DispatcherHelper.UIDispatcher.Invoke(() => ImageSelectionViewModel.RefreshImages(_imageList)); 
    } 

我想使兩個方法(1.domaminModel.Load(),2. UpdateState())在一個接一個的同一個線程上運行。而不是在UI線程上。使用異步和等待

我該怎麼做?

+0

不是問題的關鍵,但'DispatcherHelper.UIDispatcher.Invoke'沒有必要,因爲您已經在UI線程上了。我很驚訝,即使運行。 – usr

+0

需要刷新可觀察集合。別擔心。運行完全 – Gilad

+0

'UpdateState'也是'async void',與'InitData'相同?有什麼理由不使用'async Task'嗎? – Noseratio

回答

1

我想使這兩種方法(1.domaminModel.Load(),2 UpdateState())上運行一個接一個的相同的線程。不在 的UI線程上。

更新,如果你想只_domainModel.LoadImageSelectionViewModel.UpdateState到一個單獨的非UI線程中運行,那麼就這樣做:

public async override void InitData() 
{ 
    _domainModel = new DomainModel() 

    ProgressIndicatorViewModel.Start(); 
    _State = Getstate(); 
    await Task.Run(async() => 
    { 
     await _domainModel.Load(_State, ProgressIndicatorViewModel)) 
     ImageSelectionViewModel.UpdateState(_State); //returns void not a task! 
    }); 
    ProgressIndicatorViewModel.Stop(); 

    ImageSelectionViewModel.RefreshImages(_imageList); 
} 

注意您需要DispatcherHelper.UIDispatcher.Invoke()包裝即可。


如果你想的 InitData _domainModel.Load後剩下的一個單獨的線程運行:您在這裏

public async override void InitData() 
{ 
    _domainModel = new DomainModel() 

    ProgressIndicatorViewModel.Start(); 
    _State = Getstate(); 
    await Task.Run(() => _domainModel.Load(_State, 
     ProgressIndicatorViewModel)).ConfigureAwait(false); 
    ImageSelectionViewModel.UpdateState(_State); //returns void not a task! 

    DispatcherHelper.UIDispatcher.Invoke(() => 
    { 
     ProgressIndicatorViewModel.Stop(); 
     ImageSelectionViewModel.RefreshImages(_imageList) 
    }); 
} 

注意Task.Run會自動解開嵌套任務(的Task<Task<T>>)。另外,您可能需要將ProgressIndicatorViewModel.Stop()移至Dispatcher.Invoke之內。

根據內部_domainModel.Load什麼,你可能甚至不需要Task.Run

await _domainModel.Load(_State, 
    ProgressIndicatorViewModel).ConfigureAwait(false); 

一個側面說明,你應該處理您的async void InitData方法內部異常。你將無法在它之外處理它們。

+1

我認爲你的答案是錯誤的,因爲你正在同一個線程[_domainModel.Load]&[ImageSelectionViewModel.UpdateState]&[ProgressIndicatorViewModel.Stop]中執行以下行,但他希望有[_domainModel.Load]&[ImageSelectionViewModel。例如,如果一個UI線程是一個調用者線程,而ProgressIndicatorViewModel.Stop()更改一個UI,那麼你的代碼將不會被執行 –

+1

@YasserMoradi,你可能是對的,雖然我不明白爲什麼@Gilad需要'DispatcherHelper.UIDispatcher.Invoke'那麼我想他想在非UI線程上運行剩餘的方法。答解決這兩種情況。 – Noseratio

+0

'請注意,Task.Run會自動解開嵌套任務(任務>)在這裏。「這是什麼意思? –

1

考慮以下代碼:(!)

public async void Sample() 
{ 
    DoOne(); 
    await DoTwo(); 
    DoThree(); 
    Dispather.BeginInvoke(() => DoFour()); 
} 

DoOne不會UI線程,它的線程將是一個線程是方法樣品的呼叫者()執行取名爲來電線程

在客戶端的大多數情況下,調用者線程是UI線程,因爲大多數代碼都是由用戶操作(例如鼠標點擊)調用的,但這不是一個固定的行爲。

DoTwo將在一個獨立的線程來執行,很明顯,它不會在調用者的線程執行。

DoThree將在調用程序線程

DoFour將在UI線程執行的執行,但是不要緊,什麼是調用程序線程。

因此@usr的評論是完全錯誤的。

爲了實現自己的目標改變你的代碼如下:

public async override void InitData() 
    { 
     _domainModel = new DomainModel() 

     ProgressIndicatorViewModel.Start(); 
     _State = Getstate(); 
     await Task.Factory.StartNew(() => { 
      _domainModel.Load(_State, ProgressIndicatorViewModel).ContinueWith(() => { 
      ImageSelectionViewModel.UpdateState(_State); }); 
      }; 
     ProgressIndicatorViewModel.Stop(); 

     DispatcherHelper.UIDispatcher.Invoke(() => ImageSelectionViewModel.RefreshImages(_imageList)); 
    } 
+0

要使其按照您的預期工作,您需要對Task.Factory.StartNew的結果調用'Unwrap'。這是因爲'ContinueWith'返回'Task',所以'Task.Factory.StartNew'將返回'Task ',並且不等待當前版本中的內部任務。 – Noseratio

+0

@Noseratio感謝您的回覆,請注意,我的答案是概念性的,它甚至不會構建! ( - : –

+1

從概念上講,我認爲你需要在這裏等待await或單個await和unwrap,否則在await後面的代碼可能會在另一個線程上的UpdateState結束之前繼續下去 – Noseratio