2016-08-26 2 views
3

私はいつもBackgroundworkerを使用しましたが、私はasync/awaitキーワードを初めて使用しています。今、Backgroundworkerのコードをasync/await(WPF MVVMアプリケーション)にリファクタリングしようとしています。バックグラウンドワーカーをasync/awaitにリファクタリングする

GenerateCommand = new DelegateCommand(GenerateHandler, CanGenerate); 

私はおそらく私のために動作しますdevに「AsyncCommand」libに表現するが、そこで見てきた:

は、私はこのようにインスタンス化された私のVMにコマンドを得ました。

すべてのハンドラは、完了したイベントにイベントハンドラを登録し、サービスのGenerateメソッドを呼び出します。

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キーワードを使って、私の非同期メソッドを待たなければならない場所。私はworker_DoWorkを非同期としてマークし、Generateメソッドの呼び出しを待っていましたが、Generateメソッドは非同期としてもマークされていなければなりませんでした。申し訳ありません

私はあなたを混乱していますが、このすべては、ABIT私を混乱されている場合...助け非同期/のawait構文砂糖メリットがコーディングされた利便性の

+0

あなたは完全に非同期メソッドにDoWorkイベントハンドラを書き換えることにより、非同期/待つために移行することができるはずですし、あなたのコードのどこかでそれを待ってから、BackgroundWorkerを完全に削除してください。 –

+0

'GenerateHandler'と' GenerateMdfHandler'はタイプミスですか、それとも別のメソッドですか? – Sam

+0

@Samそれはタイプミスでした。 – user3292642

答えて

3

一つのため

おかげ - あなたが書くことができます通常は同期メソッドを書くのと同じように、真に非同期メソッドと同様です。

ここでは、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); 

Iが示しますアイデア、あなたの具体的な考慮なしにgeneratorService実現。あなたの最終的な実現はおそらく全く同じではありません。

いくつかの注意:

通常非同期方法はTaskまたはTask<T>を返す必要がありますが、できるだけ早くGenerateHandlerは、実際にコマンドのハンドラであるとして、それは無効リターンを持っている場合には正常ですタイプ。この例では、(簡単な言葉で)動作する方法

:UIスレッドで呼び出さGenerateHandler

Task.Runので、UIスレッドがUIイベントへの応答のための無料のまま、スレッドプールからスレッドにworker_DoWork処理を委譲します。キーワードを待つ何

は行いますTask.Runは、スレッドプールにタスクを作成した後、それだけでGenerateHandlerから返します。しかし、残りのメソッド(その場合はOnGenerationFinished)と現在の同期コンテキスト(その場合はUIスレッド)を覚えておいて、残りのメソッドはworker_DoWorkが処理を完了した後に処理されます。

しかし、あなたはOnGenerationFinished処理のためのUIスレッドを必要としない場合、あなたはは、メソッドの残りの部分を呼び出すための現在の同期コンテキストを使用していないを待つ伝えることができ、これがために何ConfigureAwait(false)です。この場合、OnGenerationFinishedはスレッドプールから別のスレッドで実行され、UIスレッドが非UIジョブの注意をそらすことはありません。

0

私はこれは良い習慣だとは思わないが、それは私のためだけで正常に動作:

void Something() 
    { 
    if (!mybworker.IsBusy()) 
    { 
     mybworker.RunWorkerAsync(); 
    } 
    while (mybworker.IsBusy()) 
    { 
    Application.DoEvents(); 
    } 
    } 
関連する問題