2012-08-13 27 views
2

我正在運行一個BackgroundWorker線程來執行耗時的任務。耗時的任務在另一個班上。我需要將在BackgroundWorker上運行的這個單獨的類的進度傳遞迴Main Form1類。我不知道如何解決這個問題。請提供建議。先謝謝你。c#BackgroundWorker調用另一個類和ProgressReport的DoWork方法

**// Main Form1 UI Class**  

    public void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e) 
    { 
     //e.Argument always contains whatever was sent to the background worker 
     // in RunWorkerAsync. We can simply cast it to its original type. 
     DataSet ds = e.Argument as DataSet; 
     this.createje.ProcessData(this.ds); 
    } 

    private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     this.progressBar1.Minimum = 0; 
     this.progressBar1.Maximum = CreateJE.max; 
     this.progressBar1.Value = e.Recno; 
    } 

    **//Other Class called CreateJE** 

    public void ProcessData(DataSet ds) 
    { 
     //Do time consuming task... 
    for (int i = 1; i <= 10; i++) 
     { 
      if (worker.CancellationPending == true) 
      { 
       e.Cancel = true; 
       break; 
      } 
      else 
      { 
       // Perform a time consuming operation and report progress. 
       System.Threading.Thread.Sleep(500); 

       **//How do I report progress back to the Main UI?** 
       //worker.ReportProgress(i * 10); 
      } 
     } 
    } 

回答

4

最乾淨,最可擴展的,解決辦法可能是讓你的ProcessData()方法引發一個事件,該BackgroundWorker被監聽。這種方式ProcessData()不依賴於BackgroundWorker作爲調用者。 (您還需要設法取消ProcessData())。如果需要,您甚至可以重新使用ProgressChangedEventArgs。例如(未經測試,但你的想法?):

partial class Form1 { 
    public void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e) { 
     //e.Argument always contains whatever was sent to the background worker 
     // in RunWorkerAsync. We can simply cast it to its original type. 
     DataSet ds = (DataSet)e.Argument; 
     var bgw = (BackgroundWorker)sender; 

     var eh = new ProgressChangedEventHandler((o,a) => bgw.ReportProgress(a.ProgressPercentage)); 
     createje.ProgressChanged += eh; 
     this.createje.ProcessData(this.ds)); 
     createje.ProgressChanged -= eh; //necessary to stop listening 
    } 

    private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     this.progressBar1.Minimum = 0; 
     this.progressBar1.Maximum = CreateJE.max; 
     this.progressBar1.Value = e.ProgressPercentage; 
    } 

} 

partial class CreateJE { 

    public event ProgressChangedEventHandler ProgressChanged; 
    protected virtual void OnProgressChanged(ProgressChangedEventArgs e) 
    { 
     var hand = ProgressChanged; 
     if(hand != null) hand(this, e); 
    } 

    public void ProcessData(DataSet ds) 
    { 
     for(int i = 1; i <= 10; i++) 
     { 
      // Perform a time consuming operation and report progress. 
      System.Threading.Thread.Sleep(500); 

      var e = new ProgressChangedEventArgs(i * 10, null); 
     } 
    } 

} 

的快速和骯髒的方式就是通過BackgroundWorker作爲參數傳遞給ProcessData()。這是恕我直言相當醜陋,但是,只能使用BackgroundWorkers,並且還強制您在一個位置(主窗體類)中定義BackgroundWorker,並在另一個位置(CreateJE類)中返回ReportProgress的值。

您也可以使用計時器並每X毫秒報告進度,查詢CreateJE對象的進度。這似乎與您的其他代碼一致。與此掛鉤是它會讓你的CreateJE類不是多線程友好的。

+0

我喜歡你的第一個建議。你能提供一個代碼示例嗎? – Shazam 2012-08-13 15:11:05

1

的最快最簡單的辦法是在CreateJE類,將報告proggress並鉤住這的BackgroundWorkerReportProgress方法來聲明delegate

class CreateJE 
{ 
    public Action<int> ReportProgressDelegate{get;set;} 

    public void ProcessData(DataSet ds) 
    { 
     for(int i = 0; i < 10; i++) 
     { 
      Thread.Sleep(500); 
      ReportProgress(i*10); 
     } 
    } 

    private void ReportProgress(int percent) 
    { 
     if(ReportProgressDelegate != null) 
      ReportProgressDelegate(percent); 
    } 
} 

在您的形式,初始化實例的ReportProgressDelegate財產(我假設this.createje指形式的字段,以便OnLoad似乎是個不錯的地方做初始化):

protected override void OnLoad(EventArgs e) 
{ 
    this.creatje.ReportProgressDelegate = worker.ReportProgress; 
} 

之後,您可以使用您已有的事件處理程序(backgroundWorker2_DoWorkbackgroundWorker2_DoWork)。

PS:您應該使用與worker.CancellationPending屬性相同的方法。