`

C#调用耗时函数时显示进度条浅探 .

    博客分类:
  • C#
 
阅读更多
最近在做一个VSS日志分析工具,使用C#进行开发,在完成了所有功能后,发现,从服务器下载VSS日志非常耗时,因为此,导致工具使用体验不好,所以,准备增加一个进度条。
鉴于C#不经常使用,一下子搞个进度条貌似比较难,而且其他的开发任务也在一并进行,所以,昨天一天,并没有多大的进展。
今天,是周末,正好可以利用,在查阅了大量网上资料以及实例后,我制作了几个实例,以备后来之用。
使用C#显示进度条,涉及到多线程编程,我只探索了使用BackgroundWorker和Thread的方法,下面分别列出。


第一种:使用BackgroundWorker进行进度条控制
BackgroundWorker对象有三个主要的事件:
DoWork - 当BackgroundWorker对象的多线程操作被执行时触发。
RunWokerCompleted - 当BackgroundWoker对象的多线程操作完成时触发。
ProgressChanged - 当BackgroundWorker对象的多线程操作状态改变时触发。
WorkerReportsProgress - 如果想让BackgroundWorker对象以异步的方式报告线程实时进度,必须将该属性的值设为true。
BackgroundWorker对象的ReportProgress方法用于向主线程返回后台线程执行的实时进度。

实例代码一,控制主窗体中的进度条显示

 

  1. publicpartialclassForm1:Form
  2. {
  3. ///<summary>
  4. ///后台线程
  5. ///</summary>
  6. privateBackgroundWorkerbkWorker=newBackgroundWorker();
  7. ///<summary>
  8. ///步进值
  9. ///</summary>
  10. privateintpercentValue=0;
  11. publicForm1()
  12. {
  13. InitializeComponent();
  14. bkWorker.WorkerReportsProgress=true;
  15. bkWorker.WorkerSupportsCancellation=true;
  16. bkWorker.DoWork+=newDoWorkEventHandler(DoWork);
  17. bkWorker.ProgressChanged+=newProgressChangedEventHandler(ProgessChanged);
  18. bkWorker.RunWorkerCompleted+=newRunWorkerCompletedEventHandler(CompleteWork);
  19. }
  20. privatevoidbtnStart_Click(objectsender,EventArgse)
  21. {
  22. percentValue=10;
  23. this.progressBar1.Maximum=1000;
  24. //执行后台操作
  25. bkWorker.RunWorkerAsync();
  26. }
  27. publicvoidDoWork(objectsender,DoWorkEventArgse)
  28. {
  29. //事件处理,指定处理函数
  30. e.Result=ProcessProgress(bkWorker,e);
  31. }
  32. publicvoidProgessChanged(objectsender,ProgressChangedEventArgse)
  33. {
  34. //bkWorker.ReportProgress会调用到这里,此处可以进行自定义报告方式
  35. this.progressBar1.Value=e.ProgressPercentage;
  36. intpercent=(int)(e.ProgressPercentage/percentValue);
  37. this.label1.Text="处理进度:"+Convert.ToString(percent)+"%";
  38. }
  39. publicvoidCompleteWork(objectsender,RunWorkerCompletedEventArgse)
  40. {
  41. this.label1.Text="处理完毕!";
  42. }
  43. privateintProcessProgress(objectsender,DoWorkEventArgse)
  44. {
  45. for(inti=0;i<=1000;i++)
  46. {
  47. if(bkWorker.CancellationPending)
  48. {
  49. e.Cancel=true;
  50. return-1;
  51. }
  52. else
  53. {
  54. //状态报告
  55. bkWorker.ReportProgress(i);
  56. //等待,用于UI刷新界面,很重要
  57. System.Threading.Thread.Sleep(1);
  58. }
  59. }
  60. return-1;
  61. }
  62. }
    public partial class Form1 : Form
    {
        /// <summary>
        /// 后台线程
        /// </summary>
        private BackgroundWorker bkWorker = new BackgroundWorker();

        /// <summary>
        /// 步进值
        /// </summary>
        private int percentValue = 0;

        public Form1()
        {
            InitializeComponent();

            bkWorker.WorkerReportsProgress = true;
            bkWorker.WorkerSupportsCancellation = true;
            bkWorker.DoWork += new DoWorkEventHandler(DoWork);
            bkWorker.ProgressChanged += new ProgressChangedEventHandler(ProgessChanged);
            bkWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteWork);
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            percentValue = 10;
            this.progressBar1.Maximum = 1000;
            // 执行后台操作
            bkWorker.RunWorkerAsync();
        }

        public void DoWork(object sender, DoWorkEventArgs e)
        {
            // 事件处理,指定处理函数
            e.Result = ProcessProgress(bkWorker, e);
        }

        public void ProgessChanged(object sender, ProgressChangedEventArgs e)
        {
            // bkWorker.ReportProgress 会调用到这里,此处可以进行自定义报告方式
            this.progressBar1.Value = e.ProgressPercentage;
            int percent = (int)(e.ProgressPercentage / percentValue);
            this.label1.Text = "处理进度:" + Convert.ToString(percent) + "%";
        }

        public void CompleteWork(object sender, RunWorkerCompletedEventArgs e)
        {
            this.label1.Text = "处理完毕!";
        }

        private int ProcessProgress(object sender, DoWorkEventArgs e)
        {
            for (int i = 0; i <= 1000; i++)
            {
                if (bkWorker.CancellationPending)
                {
                    e.Cancel = true;
                    return -1;
                }
                else
                {
                    // 状态报告
                    bkWorker.ReportProgress(i);

                    // 等待,用于UI刷新界面,很重要
                    System.Threading.Thread.Sleep(1);
                }
            }

            return -1;
        }
    }

 

下面是运行结果

实例代码二,控制弹出窗体中的进度条显示
主窗体代码:

 

  1. publicpartialclassForm1:Form
  2. {
  3. privateBackgroundWorkerbkWorker=newBackgroundWorker();
  4. privateForm2notifyForm=newForm2();
  5. publicForm1()
  6. {
  7. InitializeComponent();
  8. //使用BackgroundWorker时不能在工作线程中访问UI线程部分,
  9. //即你不能在BackgroundWorker的事件和方法中操作UI,否则会抛跨线程操作无效的异常
  10. //添加下列语句可以避免异常。
  11. CheckForIllegalCrossThreadCalls=false;
  12. bkWorker.WorkerReportsProgress=true;
  13. bkWorker.WorkerSupportsCancellation=true;
  14. bkWorker.DoWork+=newDoWorkEventHandler(DoWork);
  15. bkWorker.ProgressChanged+=newProgressChangedEventHandler(ProgessChanged);
  16. bkWorker.RunWorkerCompleted+=newRunWorkerCompletedEventHandler(CompleteWork);
  17. }
  18. privatevoidbtnStart_Click(objectsender,EventArgse)
  19. {
  20. notifyForm.StartPosition=FormStartPosition.CenterParent;
  21. bkWorker.RunWorkerAsync();
  22. notifyForm.ShowDialog();
  23. }
  24. publicvoidDoWork(objectsender,DoWorkEventArgse)
  25. {
  26. //事件处理,指定处理函数
  27. e.Result=ProcessProgress(bkWorker,e);
  28. }
  29. publicvoidProgessChanged(objectsender,ProgressChangedEventArgse)
  30. {
  31. //bkWorker.ReportProgress会调用到这里,此处可以进行自定义报告方式
  32. notifyForm.SetNotifyInfo(e.ProgressPercentage,"处理进度:"+Convert.ToString(e.ProgressPercentage)+"%");
  33. }
  34. publicvoidCompleteWork(objectsender,RunWorkerCompletedEventArgse)
  35. {
  36. notifyForm.Close();
  37. MessageBox.Show("处理完毕!");
  38. }
  39. privateintProcessProgress(objectsender,DoWorkEventArgse)
  40. {
  41. for(inti=0;i<=1000;i++)
  42. {
  43. if(bkWorker.CancellationPending)
  44. {
  45. e.Cancel=true;
  46. return-1;
  47. }
  48. else
  49. {
  50. //状态报告
  51. bkWorker.ReportProgress(i/10);
  52. //等待,用于UI刷新界面,很重要
  53. System.Threading.Thread.Sleep(1);
  54. }
  55. }
  56. return-1;
  57. }
  58. }
    public partial class Form1 : Form
    {
        private BackgroundWorker bkWorker = new BackgroundWorker();
        private Form2 notifyForm = new Form2();

        public Form1()
        {
            InitializeComponent();

            // 使用BackgroundWorker时不能在工作线程中访问UI线程部分,
            // 即你不能在BackgroundWorker的事件和方法中操作UI,否则会抛跨线程操作无效的异常
            // 添加下列语句可以避免异常。
            CheckForIllegalCrossThreadCalls = false;

            bkWorker.WorkerReportsProgress = true;
            bkWorker.WorkerSupportsCancellation = true;
            bkWorker.DoWork += new DoWorkEventHandler(DoWork);
            bkWorker.ProgressChanged += new ProgressChangedEventHandler(ProgessChanged);
            bkWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteWork);
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            notifyForm.StartPosition = FormStartPosition.CenterParent;

            bkWorker.RunWorkerAsync();
            notifyForm.ShowDialog();
        }

        public void DoWork(object sender, DoWorkEventArgs e)
        {
            // 事件处理,指定处理函数
            e.Result = ProcessProgress(bkWorker, e);
        }

        public void ProgessChanged(object sender, ProgressChangedEventArgs e)
        {
            // bkWorker.ReportProgress 会调用到这里,此处可以进行自定义报告方式
            notifyForm.SetNotifyInfo(e.ProgressPercentage, "处理进度:" + Convert.ToString(e.ProgressPercentage) + "%");
        }

        public void CompleteWork(object sender, RunWorkerCompletedEventArgs e)
        {
            notifyForm.Close();
            MessageBox.Show("处理完毕!");
        }

        private int ProcessProgress(object sender, DoWorkEventArgs e)
        {
            for (int i = 0; i <= 1000; i++)
            {
                if (bkWorker.CancellationPending)
                {
                    e.Cancel = true;
                    return -1;
                }
                else
                {
                    // 状态报告
                    bkWorker.ReportProgress(i / 10);

                    // 等待,用于UI刷新界面,很重要
                    System.Threading.Thread.Sleep(1);
                }
            }

            return -1;
        }
    }

子窗体代码

 

 

  1. publicpartialclassForm2:Form
  2. {
  3. publicForm2()
  4. {
  5. InitializeComponent();
  6. }
  7. publicvoidSetNotifyInfo(intpercent,stringmessage)
  8. {
  9. this.label1.Text=message;
  10. this.progressBar1.Value=percent;
  11. }
  12. }
   public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        public void SetNotifyInfo(int percent, string message)
        {
            this.label1.Text = message;
            this.progressBar1.Value = percent;
        }
    }

 

下面是运行结果


第二种,使用Thread来实现
使用Thread实现,虽然步骤上比较麻烦,但是调用流程比较简单,也是一种可以参考的方法
使用时,首先要定义代理以及函数,然后实现线程函数,在线程函数中调用代理,最后启动线程,传入线程函数。
下面是实例代码:

 

  1. publicpartialclassForm1:Form
  2. {
  3. privateForm2progressForm=newForm2();
  4. //代理定义,可以在Invoke时传入相应的参数
  5. privatedelegatevoidfunHandle(intnValue);
  6. privatefunHandlemyHandle=null;
  7. publicForm1()
  8. {
  9. InitializeComponent();
  10. }
  11. privatevoidbtnStart_Click(objectsender,EventArgse)
  12. {
  13. //启动线程
  14. System.Threading.Threadthread=newSystem.Threading.Thread(newSystem.Threading.ThreadStart(ThreadFun));
  15. thread.Start();
  16. }
  17. ///<summary>
  18. ///线程函数中调用的函数
  19. ///</summary>
  20. privatevoidShowProgressBar()
  21. {
  22. myHandle=newfunHandle(progressForm.SetProgressValue);
  23. progressForm.ShowDialog();
  24. }
  25. ///<summary>
  26. ///线程函数,用于处理调用
  27. ///</summary>
  28. privatevoidThreadFun()
  29. {
  30. MethodInvokermi=newMethodInvoker(ShowProgressBar);
  31. this.BeginInvoke(mi);
  32. System.Threading.Thread.Sleep(1000);//sleeptoshowwindow
  33. for(inti=0;i<1000;++i)
  34. {
  35. System.Threading.Thread.Sleep(5);
  36. //这里直接调用代理
  37. this.Invoke(this.myHandle,newobject[]{(i/10)});
  38. }
  39. }
  40. }
    public partial class Form1 : Form
    {
        private Form2 progressForm = new Form2();
        // 代理定义,可以在Invoke时传入相应的参数
        private delegate void funHandle(int nValue);
        private funHandle myHandle = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            // 启动线程
            System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(ThreadFun));
            thread.Start();
        }

        /// <summary>
        /// 线程函数中调用的函数
        /// </summary>
        private void ShowProgressBar()
        {
            myHandle = new funHandle(progressForm.SetProgressValue);
            progressForm.ShowDialog();
        }

        /// <summary>
        /// 线程函数,用于处理调用
        /// </summary>
        private void ThreadFun()
        {
            MethodInvoker mi = new MethodInvoker(ShowProgressBar);
            this.BeginInvoke(mi);

            System.Threading.Thread.Sleep(1000); // sleep to show window

            for (int i = 0; i < 1000; ++i)
            {
                System.Threading.Thread.Sleep(5);
                // 这里直接调用代理
                this.Invoke(this.myHandle, new object[] { (i / 10) });
            }
        }
    }

子窗体代码

 

 

  1. publicpartialclassForm2:Form
  2. {
  3. publicForm2()
  4. {
  5. InitializeComponent();
  6. }
  7. publicvoidSetProgressValue(intvalue)
  8. {
  9. this.progressBar1.Value=value;
  10. this.label1.Text="Progress:"+value.ToString()+"%";
  11. //这里关闭,比较好,呵呵!
  12. if(value==this.progressBar1.Maximum-1)this.Close();
  13. }
  14. }
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        public void SetProgressValue(int value)
        {
            this.progressBar1.Value = value;
            this.label1.Text = "Progress :" + value.ToString() + "%";

            // 这里关闭,比较好,呵呵!
            if (value == this.progressBar1.Maximum - 1) this.Close();
        }
    }

 

下面是运行结果图


参考资料

1. C#进度条实现实例 { http://www.csharpwin.com/csharpspace/6546r2922.shtml }
2. 使用BackgroundWorker方便地实现多线程进度条!{ http://www.coderblog.in/2011/03/backgroundworker-for-progreessbar.html }
3. 多线程:C#.NET中使用BackgroundWorker在模态对话框中显示进度条 { http://www.mysjtu.com/page/M0/S536/536907.html }
4. C#进度条在弹出窗口中显示的实现 { http://wenku.baidu.com/view/9f9d89d2240c844769eaeeff.html }

 

 

原文:http://blog.csdn.net/lightlater/article/details/8092991

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics