2016-08-26 71 views
3

我一直使用BackgroundWorker的,我是新來的異步/等待關鍵字。現在,我想從BackgroundWorker的重構一些代碼,以異步/等待(這是一個WPF MVVM應用程序)。重構BackgroundWorker的非同步的/等待

GenerateCommand = new DelegateCommand(GenerateHandler, CanGenerate); 

我見過有一個「AsyncCommand」在開發表達lib下,這可能會爲我工作:

我在虛擬機,這是實例化這樣得到的命令。

所有處理程序都會將事件處理程序註冊到完成的事件並在服務上調用生成方法。

private void GenerateHandler() 
{ 
    generatorService.GenerationFinished += OnGenerationFinished; 
    generatorService.Generate(mDataFields, mGenerateFilesViewModel, mAmount);  
} 

然後,服務的生成方法啓動一個BackgroundWorker:

public void Generate(IEnumerable<IDataField> dataFields, IGenerateFilesViewModel generateFilesViewModel, int amount) 
{ 
    BackgroundWorker worker = new BackgroundWorker(); 
    worker.DoWork += worker_DoWork; 
    worker.RunWorkerAsync(); 
} 

的DoWork的方法不消耗我不確定我必須標記該方法中,時間任務

private void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    GenerateCommand generateCommand = null; 
    if (mUploadFiles) 
    { 
    generateCommand = new GenerateCommand(mDataFields, mOutputDirectory, mTemplateFileName, mAmount, mSelectedCollection, mSelectedAccountKey); 
    } 
    else 
    { 
    generateCommand = new GenerateCommand(mDataFields, mOutputDirectory, mTemplateFileName, mAmount); 
    } 

    try 
    { 
    generateCommand.Execute(); 
    } 
    catch (SEHException ex) 
    { 
    Console.WriteLine(String.Format("Generation of files threw an exception. {0}", ex.Message)); 
    } 
} 

與async關鍵字現在和我必須等待我的異步方法。我tryed以紀念worker_DoWork爲異步和等待的生成方法的調用,但隨後的生成方法,已被標記爲異步太爲了awaitable在VM的GenerateHandler?

很抱歉,如果我迷惑你,但是這一切都是升技混淆我...

感謝您的幫助

+0

您應該能夠完全遷移到異步/通過改寫DoWork的事件處理異步方法的await和在代碼中的某處等待,然後完全刪除BackgroundWorker。 –

+0

'GenerateHandler'和'GenerateMdfHandler'是一個錯字還是他們是不同的方法? – Sam

+0

@Sam這是一個錯字,很抱歉 – user3292642

回答

3

一個異步/ AWAIT語法糖好處就是方便編碼的 - 你可以寫真正的異步方法就像通常寫同步方法一樣。

在這裏你有worker_DoWork重載荷和OnGenerationFinished最後的方法。所以,你的GenerateHandler可以是這樣的:

private async void GenerateHandler() 
{ 
    await Task.Run(() => worker_DoWork()); 

    OnGenerationFinished(); 
} 

如果您OnGenerationFinished方法邏輯並不直接改變任何UI元素,你甚至可以更用ConfigureAwait卸載UI線程:

await Task.Run(() => worker_DoWork()).ConfigureAwait(false); 

在這裏,我展示的想法,而不考慮你的特定的實現。你的最終實現可能不完全相同。

一些注意事項:

通常異步方法應該返回TaskTask<T>,但只要GenerateHandler實際上是命令的處理程序,它是在這種情況下,正常的有無效回報類型。

如何這個例子就可以了(在簡單的話):

GenerateHandler在UI線程調用後,Task.Run將委託worker_DoWork處理來自線程池的線程,因此UI線程響應UI事件仍然是免費的。

什麼等待關鍵字做:Task.Run在線程池創建任務後,它只是從GenerateHandler返回。但是它記得方法的其餘部分(在這種情況下爲OnGenerationFinished)和當前同步上下文(在這種情況下是UI線程),其中在worker_DoWork將完成該工作之後將處理該方法的其餘部分。

但是,如果你不需要UI線程OnGenerationFinished處理,你可以告訴等待不使用當前同步上下文調用方法的其餘部分,這是ConfigureAwait(false)的。在這種情況下,OnGenerationFinished將在線程池中的另一個線程中執行,從而使UI線程不會分散非UI作業。

0

我不認爲這是一個很好的做法,但它工作得很好,對我來說:

void Something() 
    { 
    if (!mybworker.IsBusy()) 
    { 
     mybworker.RunWorkerAsync(); 
    } 
    while (mybworker.IsBusy()) 
    { 
    Application.DoEvents(); 
    } 
    }