2011-08-02 68 views
2

我有一些做東西的類,通常是遍歷一個記錄集併爲每條記錄調用一個或兩個webservice。倒立的後臺工作人員

目前這一切都在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(); 
    } 

我會繼續前進,這樣做,但不要不想重塑。

我正在尋找將沿着「是的,喬做了很好的實施是(在這裏)」或線「這是一個代理的Widget模式,去了解它(這裏)」

+0

也許會添加一個小的(簡化的)示例? –

+0

在本例中,添加了UnlockCalls,可以使用SQL語句獲取多達1000行,使用webservice解鎖每一個,並返回它處理的行數。 我也想實現/使用pushToBackground類中的cancel和progress功能。 –

回答

1

每個操作需要實現以下接口:

/// <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; } 
} 

此方式隔開的從處理的步驟的枚舉。

下面是一個簡單的操作:

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。

在這裏有一些編碼,但它更清潔和有效。而且比使用後臺工作者更可維護(這只是真正用於小型任務)。

+0

正如我所說的,「在我繼續前進並重新發明車輪之前」。如果我正在進行重新創建,使用線程將是一個很好的方法。 –