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

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

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

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

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

  1. public partial class Form1 : Form 
  2.     /// <summary> 
  3.     /// 后台线程 
  4.     /// </summary> 
  5.     private BackgroundWorker bkWorker = new BackgroundWorker(); 
  6.  
  7.     /// <summary> 
  8.     /// 步进值 
  9.     /// </summary> 
  10.     private int percentValue = 0; 
  11.  
  12.     public Form1() 
  13.     { 
  14.         InitializeComponent(); 
  15.  
  16.         bkWorker.WorkerReportsProgress = true
  17.         bkWorker.WorkerSupportsCancellation = true
  18.         bkWorker.DoWork += new DoWorkEventHandler(DoWork); 
  19.         bkWorker.ProgressChanged += new ProgressChangedEventHandler(ProgessChanged); 
  20.         bkWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteWork); 
  21.     } 
  22.  
  23.     private void btnStart_Click(object sender, EventArgs e) 
  24.     { 
  25.         percentValue = 10; 
  26.         this.progressBar1.Maximum = 1000; 
  27.         // 执行后台操作 
  28.         bkWorker.RunWorkerAsync(); 
  29.     } 
  30.  
  31.     public void DoWork(object sender, DoWorkEventArgs e) 
  32.     { 
  33.         // 事件处理,指定处理函数 
  34.         e.Result = ProcessProgress(bkWorker, e); 
  35.     } 
  36.  
  37.     public void ProgessChanged(object sender, ProgressChangedEventArgs e) 
  38.     { 
  39.         // bkWorker.ReportProgress 会调用到这里,此处可以进行自定义报告方式 
  40.         this.progressBar1.Value = e.ProgressPercentage; 
  41.         int percent = (int)(e.ProgressPercentage / percentValue); 
  42.         this.label1.Text = "处理进度:" + Convert.ToString(percent) + "%"
  43.     } 
  44.  
  45.     public void CompleteWork(object sender, RunWorkerCompletedEventArgs e) 
  46.     { 
  47.         this.label1.Text = "处理完毕!"
  48.     } 
  49.  
  50.     private int ProcessProgress(object sender, DoWorkEventArgs e) 
  51.     { 
  52.         for (int i = 0; i <= 1000; i++) 
  53.         { 
  54.             if (bkWorker.CancellationPending) 
  55.             { 
  56.                 e.Cancel = true
  57.                 return -1; 
  58.             } 
  59.             else 
  60.             { 
  61.                 // 状态报告 
  62.                 bkWorker.ReportProgress(i); 
  63.  
  64.                 // 等待,用于UI刷新界面,很重要 
  65.                 System.Threading.Thread.Sleep(1); 
  66.             } 
  67.         } 
  68.  
  69.         return -1; 
  70.     } 
    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. public partial class Form1 : Form 
  2.     private BackgroundWorker bkWorker = new BackgroundWorker(); 
  3.     private Form2 notifyForm = new Form2(); 
  4.  
  5.     public Form1() 
  6.     { 
  7.         InitializeComponent(); 
  8.  
  9.         // 使用BackgroundWorker时不能在工作线程中访问UI线程部分, 
  10.         // 即你不能在BackgroundWorker的事件和方法中操作UI,否则会抛跨线程操作无效的异常 
  11.         // 添加下列语句可以避免异常。 
  12.         CheckForIllegalCrossThreadCalls = false
  13.  
  14.         bkWorker.WorkerReportsProgress = true
  15.         bkWorker.WorkerSupportsCancellation = true
  16.         bkWorker.DoWork += new DoWorkEventHandler(DoWork); 
  17.         bkWorker.ProgressChanged += new ProgressChangedEventHandler(ProgessChanged); 
  18.         bkWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteWork); 
  19.     } 
  20.  
  21.     private void btnStart_Click(object sender, EventArgs e) 
  22.     { 
  23.         notifyForm.StartPosition = FormStartPosition.CenterParent; 
  24.  
  25.         bkWorker.RunWorkerAsync(); 
  26.         notifyForm.ShowDialog(); 
  27.     } 
  28.  
  29.     public void DoWork(object sender, DoWorkEventArgs e) 
  30.     { 
  31.         // 事件处理,指定处理函数 
  32.         e.Result = ProcessProgress(bkWorker, e); 
  33.     } 
  34.  
  35.     public void ProgessChanged(object sender, ProgressChangedEventArgs e) 
  36.     { 
  37.         // bkWorker.ReportProgress 会调用到这里,此处可以进行自定义报告方式 
  38.         notifyForm.SetNotifyInfo(e.ProgressPercentage, "处理进度:" + Convert.ToString(e.ProgressPercentage) + "%"); 
  39.     } 
  40.  
  41.     public void CompleteWork(object sender, RunWorkerCompletedEventArgs e) 
  42.     { 
  43.         notifyForm.Close(); 
  44.         MessageBox.Show("处理完毕!"); 
  45.     } 
  46.  
  47.     private int ProcessProgress(object sender, DoWorkEventArgs e) 
  48.     { 
  49.         for (int i = 0; i <= 1000; i++) 
  50.         { 
  51.             if (bkWorker.CancellationPending) 
  52.             { 
  53.                 e.Cancel = true
  54.                 return -1; 
  55.             } 
  56.             else 
  57.             { 
  58.                 // 状态报告 
  59.                 bkWorker.ReportProgress(i / 10); 
  60.  
  61.                 // 等待,用于UI刷新界面,很重要 
  62.                 System.Threading.Thread.Sleep(1); 
  63.             } 
  64.         } 
  65.  
  66.         return -1; 
  67.     } 
    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. public partial class Form2 : Form 
  2.      public Form2() 
  3.      { 
  4.          InitializeComponent(); 
  5.      } 
  6.  
  7.      public void SetNotifyInfo(int percent, string message) 
  8.      { 
  9.          this.label1.Text = message; 
  10.          this.progressBar1.Value = percent; 
  11.      } 
   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. public partial class Form1 : Form 
  2.     private Form2 progressForm = new Form2(); 
  3.     // 代理定义,可以在Invoke时传入相应的参数 
  4.     private delegate void funHandle(int nValue); 
  5.     private funHandle myHandle = null
  6.  
  7.     public Form1() 
  8.     { 
  9.         InitializeComponent(); 
  10.     } 
  11.  
  12.     private void btnStart_Click(object sender, EventArgs e) 
  13.     { 
  14.         // 启动线程 
  15.         System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(ThreadFun)); 
  16.         thread.Start(); 
  17.     } 
  18.  
  19.     /// <summary> 
  20.     /// 线程函数中调用的函数 
  21.     /// </summary> 
  22.     private void ShowProgressBar() 
  23.     { 
  24.         myHandle = new funHandle(progressForm.SetProgressValue); 
  25.         progressForm.ShowDialog(); 
  26.     } 
  27.  
  28.     /// <summary> 
  29.     /// 线程函数,用于处理调用 
  30.     /// </summary> 
  31.     private void ThreadFun() 
  32.     { 
  33.         MethodInvoker mi = new MethodInvoker(ShowProgressBar); 
  34.         this.BeginInvoke(mi); 
  35.  
  36.         System.Threading.Thread.Sleep(1000); // sleep to show window 
  37.  
  38.         for (int i = 0; i < 1000; ++i) 
  39.         { 
  40.             System.Threading.Thread.Sleep(5); 
  41.             // 这里直接调用代理 
  42.             this.Invoke(this.myHandle, new object[] { (i / 10) }); 
  43.         } 
  44.     } 
    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. public partial class Form2 : Form 
  2.     public Form2() 
  3.     { 
  4.         InitializeComponent(); 
  5.     } 
  6.  
  7.     public void SetProgressValue(int value) 
  8.     { 
  9.         this.progressBar1.Value = value; 
  10.         this.label1.Text = "Progress :" + value.ToString() + "%"
  11.  
  12.         // 这里关闭,比较好,呵呵! 
  13.         if (value == this.progressBar1.Maximum - 1) this.Close(); 
  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 }


查看评论

  暂无评论

发表评论
  • 用 户 名:
  • hewusheng10
  •  
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
TOP
  • 个人资料
    • 访问:21609次
    • 积分:649分
    • 排名:第16888名
    • 原创:39篇
    • 转载:3篇
    • 译文:0篇
    • 评论:18条
  • 推荐文章
    • 最新评论
    • 有情连接
    公司简介| 招贤纳士| 广告服务| 银行汇款帐号| 联系方式| 版权声明| 法律顾问| 问题报告
    QQ客服 微博客服 论坛反馈 服务热线:400-600-2320
    京 ICP 证 070598 号
    北京创新乐知信息技术有限公司 版权所有
    世纪乐知(北京)网络技术有限公司 提供技术支持
    江苏乐知网络技术有限公司 提供商务支持
    Copyright © 1999-2012, CSDN.NET, All Rights Reserved GongshangLogo
    您有 0条新通知
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值