2012-07-28 87 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