2010-12-16 11 views
1

ファイルを読み込んでDBにレコードを挿入するWPFアプリケーションにインポートファイルメソッドがあります。WPF:呼び出す待ち行列に何もない場合、Dispatcher.BeginInvoke *のみを呼び出す方法?

このメソッドは、BackgroundWorkerオブジェクトで実行されます。 Dispatcher.Invokeコールの中で進行状況バーが更新されています。私が実行している場合は、200kのレコードをインポートするのに1分かかります。進捗状況が表示されない場合は、わずか4〜5秒かかります。そしてとBackgroundの優先度を使用すると、同じ4〜5秒かかりますが、プログレスバーとカウンタは更新されており、約1分かかります。だから、あいまいなことに、ここではUIが問題です。

もう1つの問題は、進捗状況を示す必要があるため、Dispatcher.BeginInvokeを使用する方法があれば考えていましたが、まずキューに何かがあるかどうかを確認します。次のように動作します:1秒目に1%完了、2秒後に50%完了、4秒目に100%完了)。

これに関する助力?

ありがとうございます!

コードを見ずに言うことは不可能

答えて

2

が、

私はDispatcher.Invokeコール

なぜ内部で更新されているプログレスバーがありますか?それはReportProgressが対象です。

私が推測しなければならないことは、あなたが進歩を頻繁に報告していると言います。たとえば、すべてのレコードの後に​​進捗状況を報告しないでください。ただし、100回のバッチ以降は報告しないでください。

2

問題は、コールバックがディスパッチャにキューイングされていることです。それぞれが画面を再描画する原因になり、バックグラウンド優先順位になっているので、次の処理が処理される前にその再描画が完了するのを待つため、コールバックごとに再描画する必要があります。

ディスパッチャキューに何もないことを待つのではなく、前回の進行状況コールバックが処理されるまで待ってから新しい通知を送信してください。これにより、一度に複数のアクティブが存在することがないので、キューに入れられません。

コールバックをポストし、処理後にクリアするときに、フラグを設定することでこれを行うことができます。そこ...私は単にバックグラウンドスレッドでの進捗カウンタを(それが唯一のカウンタへの書き込み)を更新、およびUIは読まなければならない

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    var pending = false; 
    for (int i = 0; i < 1000000; i++) 
    { 
     // Do some work here 
     // ... 
     // Only report progress if there is no progress report pending 
     if (!pending) 
     { 
      // Set a flag so we don't post another progress report until 
      // this one completes, and then post a new progress report 
      pending = true; 
      var currentProgress = i; 
      Dispatcher.BeginInvoke(new Action(() => 
      { 
       // Do something with currentProgress 
       progressBar.Value = currentProgress; 
       // Clear the flag so that the BackgroundWorker 
       // thread will post another progress report 
       pending = false; 
      }), DispatcherPriority.Background); 
     } 
    } 
} 
2

(読み取り専用)タイマーごとに500ミリ秒かそこら例えば:それより速く更新する理由はありません。また、1つのスレッドは書き込み専用で、1つは読み取り専用であるため、スレッドに関する問題は必要ありません。コードは大幅に単純化され、よりクリーンでメンテナンス性が向上します。

-Chert Pellett

0

私はちょうど同じケースを解決しますが、BeginInvokeによって返されるオブジェクトを使用して、そして私はそれがあまりにも非常にエレガントだと思います!

DispatcherOperation uiOperation = null; 
while (…) 
{ 
    … 
    if (uiOperation == null || uiOperation.Status == DispatcherOperationStatus.Completed || uiOperation.Status == DispatcherOperationStatus.Aborted) 
    { 
     uiOperation = uiElement.Dispatcher.BeginInvoke(…); 
    } 
} 

プログレスバーは少しチョッパーになりますが、滑らかではありませんが、飛びます。私の場合、コードはStreamReader.ReadLine()を使ってテキストファイルから行ごとに解析します。すべての行を読み込んだ後にプログレスバーを更新すると、プログレスバーが途中まで塗りつぶされる前に読み取り操作が完了します。同期Dispatcher.Invoke(…)を使用すると、操作全体が100 KiB/sに低下しますが、プログレスバーは進行状況を正確に追跡します。上記のソリューションを使用して、私のアプリケーションはわずか3つのプログレスバーの更新で1秒間に8,000 KiBの解析を完了しました。

BackgroundWorker.ReportProgress(…)の使用との1つの違いは、プログレスバーが長時間実行される操作でより細かい詳細を表示できることです。 BackgroundWorker.ReportProgress(…)は、0%から100%まで1%単位で進捗状況を報告することに限定されています。プログレスバーが100を超える操作を表す場合は、より細かい値が望ましいです。もちろん、それはpercentProgress引数を使用せず、代わりにuserStateBackgroundWorker.ReportProgress(…)を渡すことによっても達成できます。

関連する問題