4

私はWinformアプリケーションに取り組んでいます。は、 BackgroundWorkerスレッドMethodによって開始されます。ごめんなさい。これについては前に触れませんでした。

private void Method()
{
 tasks[i] = Task.Factory
           .StartNew(() => fileProcessor.ProcessEachMachine(mdetail))
           .ContinueWith(UpdateLabel, TaskContinuationOptions.OnlyOnRanToCompletion);
}

長時間実行する関数がありますProcessEachMachine。継続機能UpdateLabelでUIlabelにアクセスしてステータスを更新したい。

private void UpdateLabel()
{
   progressLbl.Text = "updated";
}

しかし、ラベルは更新されていません。UILabelにアクセスしてそのテキストを更新する方法。

4

1 に答える 1

9

ContinueWithでTaskScheduler.FromCurrentSynchronizationContextを設定する必要があります。そうしないと、UIコンテキストで実行されません。これは、ContinueWithへのこの呼び出しに使用する必要があるオーバーライドに関するMSDNです

最終的には次のようになります。

.ContinueWith(UpdateLabel, null, 
    TaskContinuationOptions.OnlyOnRanToCompletion,
    TaskScheduler.FromCurrentSynchronizationContext());

何も起こっていないように見えるかもしれませんが、TPLは現在クロススレッド例外を飲み込んでいます。各結果を検査したり、その例外をチェックしたりしない場合は、おそらくUnobservedTaskExceptionを使用する必要があります。そうしないと、ガベージコレクションが発生すると、例外が発生します...デバッグが困難なエラーが発生する可能性があります。

アップデート

バックグラウンドワーカーによってセットアップおよび開始されるメインタスクに関する更新に基づいて、私の主な質問は、なぜこれがタスクを使用して開始できなかったのかということです。実際、にそれ以上ない場合Method、これは実際には単なる二重の作業であり、他の開発者を混乱させる可能性があります。すでに非同期で開始されているので、backgroundworker内で作業を行い、 OnCompleteメソッドを使用してみませんかUpdateLabel(バックグラウンドワーカーはすでにコンテキストを認識しているため)。

ただし、主な問題は同じです。したがって、TPLを使用する必要があると思われる場合は、他の解決策をいくつか示します。

  1. InvokeUpdateLabelメソッド内でメインUIスレッドに戻ることができます
  2. 現在のコンテキストをbackgroundworkerに渡し、代わりにそれを使用できます
  3. Wait元のタスクに戻ってから、ワーカーのoncompleteイベントを使用してラベルを更新できます。

これが私がこれを行う方法です(すべての擬似コード)

バックグラウンドワーカーメソッド:

Method() called because of Background worker

private void Method()
{
    fileProcessor.ProcessEachMachine(mdetail);
}

Wire up background worker's OnRunWorkerCompleted:

if(!e.Cancelled && !e.Error)
    UpdateLabel();

タスクのみの方法

Call Method() from the main thread and just let the TPL do its work :)

Task.Factory.StartNew(() => fileProcessor.ProcessEachMachine(mdetail))
       .ContinueWith((precedingTask)=>{if(!precedingTask.Error)UpdateLabel;}, 
           null, TaskContinuationOptions.OnlyOnRanToCompletion,
           TaskScheduler.FromCurrentSynchronizationContext());
于 2012-04-23T18:15:26.120 に答える