2012-07-28 106 views
1

我想添加多個進度條到一個WinForm中,以便監視三個嵌套循環中可能長的進程。我推測,我應該能夠只使用一個後臺工作線程,是下面的實現可以接受的:一個後臺工作線程和多個進度條

這裏是我所在班級的工作正在做:

class Class1 
    { 
     public static void UpdatePB(BackgroundWorker worker) 
     { 
      for (int i = 1; i <= 10; i++) 
      { 
       for (int ii = 1; ii <= 10; ii++) 
       { 
        for (int iii = 1; iii <= 10; iii++) 
        { 
         Thread.Sleep(10); 
         worker.ReportProgress(iii, "PB3"); 
        } 
        Thread.Sleep(10); 
        worker.ReportProgress(ii, "PB2"); 
       } 
       Thread.Sleep(10); 
       worker.ReportProgress(i, "PB1"); 
      } 
     } 

,這裏是BackgroundWorker的ProgressChanged事件:

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     // Change the value of the ProgressBar to the BackgroundWorker progress. 
     switch (e.UserState.ToString()) 
     { 
      case "PB1": 
       progressBar1.Value = e.ProgressPercentage; 
       this.label1.Text = e.ProgressPercentage.ToString(); 
       break; 
      case "PB2": 
       progressBar2.Value = e.ProgressPercentage; 
       this.label2.Text = e.ProgressPercentage.ToString(); 
       break; 
      case "PB3": 
       progressBar3.Value = e.ProgressPercentage; 
       this.label3.Text = e.ProgressPercentage.ToString(); 
       break; 
     } 

     Application.DoEvents(); 
    } 
+0

當你運行它時會發生什麼?結果是你想要的嗎? (我不這麼認爲)。請更具體地說明你想達到的目標。 – usr 2012-07-28 13:41:58

+0

是的,它工作正常,但我想確保這是一個適當和標準的做法。基本上,我想監視一個長時間運行的方法中的三個不同步驟,我想調用另一個線程上的Progress Bar更新,以便更新更頻繁。 – 2012-07-28 13:44:01

回答

3

好吧,經過很多小時的搜索,我發現這個LINK,使我能夠弄清楚我做錯了什麼。基本上,我在做的是在BackgroundWorker線程上運行進度條,同時仍然在主UI線程上運行進程。我意識到這不是我應該做的,所以我現在在BackgroundWorker線程上運行所有的東西。另外,你會在我的代碼示例中看到,我需要維護兩個單獨的進度條並使用狀態信息更新richtext框。我能夠很容易地實現這個功能。這是我的最終解決方案:

using System; 
using System.ComponentModel; 
using System.Windows.Forms; 

namespace BackgroundWorkerThreadExample 
{ 
    public partial class Form1 : Form 
    { 
     public delegate void ProgressUpdatedCallaback(ProgressUpdatedEventArgs progress); 
     BackgroundWorker bw = new BackgroundWorker(); 

     public Form1() 
     { 
      InitializeComponent(); 
      bw.WorkerReportsProgress = true; 
      bw.WorkerSupportsCancellation = true; 
      bw.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork); 
      bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted); 
     } 

     private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
     { 
      DatabaseProcessor.ProgressUpdated += new DatabaseProcessor.ProgressUpdatedEvent(ProgressUpdated); 
      DatabaseProcessor.GetData(); 
     } 

     private void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) 
     { 
      bw.Dispose(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      bw.RunWorkerAsync(); 
     } 

     private void Form1_FormClosing(object sender, FormClosingEventArgs e) 
     { 
      if (bw.IsBusy == true) 
      { 
       bw.CancelAsync(); 
      } 
      bw.Dispose(); 
     } 

     private void ProgressUpdated(ProgressUpdatedEventArgs progressUpdated) 
     { 
      if (InvokeRequired) 
      { 
       Invoke(new ProgressUpdatedCallaback(this.UpdateProgress), new object[] { progressUpdated }); 
      } 
      else 
      { 
       UpdateProgress(progressUpdated); 
      } 
     } 

     private void UpdateProgress(ProgressUpdatedEventArgs args) 
     { 
      ProgressBar pb = new ProgressBar(); 
      Label lb = new Label(); 

      if (args.Message == "") 
      { 
       if (args.PBNum == 1) 
       { 
        pb = progressBar1; 
        lb = label1; 
       } 
       else if (args.PBNum == 2) 
       { 
        pb = progressBar2; 
        lb = label2; 
       } 

       if (pb.Maximum != args.Total) 
       { 
        // initial setup 
        pb.Minimum = 0; 
        pb.Maximum = args.Total; 
        pb.Style = ProgressBarStyle.Continuous; 
       } 

       pb.Value = args.Processed; 

       if (args.Total > 0) 
       { 
        double progress = args.Processed/(args.Total * 1.0); 
        lb.Text = progress.ToString("P2"); 
       } 
      } 
      else 
      { 
       this.richTextBox1.Text += args.Message; 
       //Goto last line 
       this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length; 
       this.richTextBox1.ScrollToCaret(); 
      } 
      //Application.DoEvents(); 
     } 
    } 

    public static class DatabaseProcessor 
    { 
     public delegate void ProgressUpdatedEvent(ProgressUpdatedEventArgs progressUpdated); 
     public static event ProgressUpdatedEvent ProgressUpdated; 

     public static void GetData() 
     { 
      int total = 126; 
      Random randomGenerator = new Random(); 
      for (int i = 0; i < total; i++) 
      { 
       // Do some processing here 
       double delay = (double)randomGenerator.Next(2) + randomGenerator.NextDouble(); 
       int sleep = (int)delay * 1000; 
       System.Threading.Thread.Sleep(sleep); 
       RaiseEvent(1, total, i + 1); 
       RaiseEvent(0, 0, 0, string.Format("Processing Item {0} \r\n", i + 1)); 

       for (int ii = 0; ii < total; ii++) 
       { 
        // Do some processing here 
        double delay2 = (double)randomGenerator.Next(2) + randomGenerator.NextDouble(); 
        int sleep2 = (int)delay2 * 10; 
        System.Threading.Thread.Sleep(sleep2); 
        RaiseEvent(2, total, ii + 1); 
       } 
      } 
     } 

     private static void RaiseEvent(int pbNum, int total, int current, string message = "") 
     { 
      if (ProgressUpdated != null) 
      { 
       ProgressUpdatedEventArgs args = new ProgressUpdatedEventArgs(pbNum, total, current, message); 
       ProgressUpdated(args); 
      } 
     } 
    } 

    public class ProgressUpdatedEventArgs : EventArgs 
    { 
     public ProgressUpdatedEventArgs(int pbNum, int total, int progress, string message = "") 
     { 
      this.PBNum = pbNum; 
      this.Total = total; 
      this.Processed = progress; 
      this.Message = message; 
     } 
     public string Message { get; private set; } 
     public int PBNum { get; private set; } 

     public int Processed { get; private set; } 
     public int Total { get; private set; } 
    } 
} 
+0

我仍然試圖圍繞代表部分,但它確實是我所需要的。 – 2012-07-30 18:05:41

1

那麼,你顯示一個虛假的進度條......如果這就是你想要的,那麼這個一般的方法是可以的。以下是兩項改進:

  1. 請勿使用DoEvents。相反,只要保持UI的消息循環暢通無阻。事件賬單立即得到處理。
  2. 有些人可能更喜歡在適當的時間間隔設置一個或三個定時器的解決方案。我認爲這會更好,因爲你不需要後臺線程,而且他們更精確。這就是說,我認爲你的方法在這種情況下是可讀的,可維護的並且通常很好。
+0

感謝您的回覆!我將如何去實施這些項目? – 2012-07-28 13:49:06

+0

要麼通過詢問有關這些主題的具體問題,要麼通過在其中有大量網頁上查找教程。 – usr 2012-07-28 14:24:48

+0

也許但我還沒有找到任何幫助過我的東西。這是我的最後一招,我希望有人能夠「開燈」這麼說。 – 2012-07-28 14:40:18