2011-08-02 14 views
2

私は多くのクラスを持っています。通常、レコードセットをステップ実行し、Webサービスを呼び出すか、レコードごとに2つのクラスを呼び出します。倒立したバックグラウンドワーカー

これはすべてGUIスレッドで実行され、ペイントをハングします。最初の考えは、BackgroundWorkerを使用して素敵な進捗バーを実装し、エラーや完了などを処理することでした。

コードが画面に表示されるとすぐに、匂いがかかり始めました。私は、各クラスに多くのバックグラウンドワーカーを書いていました.bw_DoWorkメソッドの大部分のProcessRowsメソッドを繰り返し、より良い方法があるはずだと考えていました。おそらくすでに完了しているはずです。

バックグラウンドワーカーを分離するクラスのパターンや実装があるのですがibackgroundableなどのインターフェイスを実装するクラスが必要ですが、クラスはスタンドアロンで実行でき、インターフェイスを実装するために最小限の変更が必要です。

編集:@Henkによって要求された簡単な例:私が持っている

private void buttonUnlockCalls_Click(object sender, EventArgs e) 
    { 
     UnlockCalls unlockCalls = new UnlockCalls(); 
     unlockCalls.MaxRowsToProcess = 1000; 
     int processedRows = unlockCalls.ProcessRows(); 
     this.textProcessedRows.text = processedRows.ToString(); 
    } 

私は私がしたいと思う:

private void buttonUnlockCalls_Click(object sender, EventArgs e) 
    { 
     UnlockCalls unlockCalls = new UnlockCalls(); 
     unlockCalls.MaxRowsToProcess = 1000; 

     PushToBackground pushToBackground = new PushToBackground(unlockCalls) 
     pushToBackground.GetReturnValue = pushToBackground_GetReturnValue; 
     pushToBackground.DoWork(); 
    } 

    private void pushToBackground_GetReturnValue(object sender, EventArgs e) 
    { 
     int processedRows = e.processedRows; 
     this.textProcessedRows.text = processedRows.ToString(); 
    } 

私が先に行くとこれを行うが、ドン可能性があり再考したくない。

私がまたは「はい、ジョーはその(ここ)の優れた実装をした」の線に沿って

+0

小さな(簡略化した)例を追加することはできますか? –

+0

この例では、UnlockCallsがSQL文で最大1000行を取得し、Webサービスでそれぞれのロックを解除し、処理した行の数を返します。 私はまた、キャンセル/進捗機能をpushToBackgroundクラスで実装/使用したいと思っています。 –

答えて

1

各操作は、以下のインターフェースを実装する必要があります。ここで

はサンプル動作です:

class SampleOperation : ISteppedOperation 
{ 
    private int maxSteps = 100; 

    //// The basic way of doing work that I want to monitor 
    //public void DoSteppedWork() 
    //{ 
    // for (int currentStep = 0; currentStep < maxSteps; currentStep++) 
    // { 
    //  System.Threading.Thread.Sleep(100); 
    // } 
    //} 

    // The same thing broken down to implement ISteppedOperation 
    private int currentStep = 0; // before the first step 
    public bool MoveNext() 
    { 
     if (currentStep == maxSteps) 
      return false; 
     else 
     { 
      currentStep++; 
      return true; 
     } 
    } 

    public void ProcessCurrent() 
    { 
     System.Threading.Thread.Sleep(100); 
    } 

    public int StepCount 
    { 
     get { return maxSteps; } 
    } 

    public int CurrentStep 
    { 
     get { return currentStep; } 
    } 

    // Re-implement the original method so it can still be run synchronously 
    public void DoSteppedWork() 
    { 
     while (MoveNext()) 
      ProcessCurrent(); 
    } 
} 

これは、このようなフォームから呼び出すことができます。

private void BackgroundWorkerButton_Click(object sender, EventArgs eventArgs) 
{ 
    var operation = new SampleOperation(); 

    BackgroundWorkerButton.Enabled = false; 

    BackgroundOperation(operation, (s, e) => 
     { 
      BackgroundWorkerButton.Enabled = true; 
     }); 
} 

private void BackgroundOperation(ISteppedOperation operation, RunWorkerCompletedEventHandler runWorkerCompleted) 
{ 
    var backgroundWorker = new BackgroundWorker(); 

    backgroundWorker.RunWorkerCompleted += runWorkerCompleted; 
    backgroundWorker.WorkerSupportsCancellation = true; 
    backgroundWorker.WorkerReportsProgress = true; 

    backgroundWorker.DoWork += new DoWorkEventHandler((s, e) => 
    { 
     while (operation.MoveNext()) 
     { 
      operation.ProcessCurrent(); 

      int percentProgress = (100 * operation.CurrentStep)/operation.StepCount; 
      backgroundWorker.ReportProgress(percentProgress); 

      if (backgroundWorker.CancellationPending) break; 
     } 
    }); 

    backgroundWorker.ProgressChanged += new ProgressChangedEventHandler((s, e) => 
    { 
     var progressChangedEventArgs = e as ProgressChangedEventArgs; 
     this.progressBar1.Value = progressChangedEventArgs.ProgressPercentage; 
    }); 

    backgroundWorker.RunWorkerAsync(); 
} 

)私はまだそれを行っていないが、私は(BackgroundOperationを移動することがあります独自のクラスに変換し、操作をキャンセルするメソッドを実装します。

0

「それはプロキシウィジェットパターンだが、(ここでは)それについて読んで行く」でしょう探している答え私は私の非UIコードを新しいクラスに入れ、スレッド(バックグラウンドワーカーではない)を使用します。進捗状況を表示するには、新しいクラスのイベントをUIに戻し、Dispatcher.Invokeを使用してUIを更新します。

これには少しのコードがありますが、よりクリーンで機能します。バックグラウンドワーカーを使用するよりも保守性が向上します(これは実際には小さなタスク用です)。

/// <summary> 
/// Allows progress to be monitored on a multi step operation 
/// </summary> 
interface ISteppedOperation 
{ 
    /// <summary> 
    /// Move to the next item to be processed. 
    /// </summary> 
    /// <returns>False if no more items</returns> 
    bool MoveNext(); 

    /// <summary> 
    /// Processes the current item 
    /// </summary> 
    void ProcessCurrent(); 

    int StepCount { get; } 
    int CurrentStep { get; } 
} 

これは処理のステップの列挙をseperates:

+0

私が言うように、「前に進み、ホイールを再構築する前に」。私が再考しているかどうかを調べるには、スレッドを使うのが良い方法でしょう。 –

関連する問題