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


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


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

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

    [csharp] view plaincopy
     
    1. public partial class Form1 : Form  
    2. {  
    3.     /// <summary>  
    4.     /// 后台线程  
    5.     /// </summary>  
    6.     private BackgroundWorker bkWorker = new BackgroundWorker();  
    7.   
    8.     /// <summary>  
    9.     /// 步进值  
    10.     /// </summary>  
    11.     private int percentValue = 0;  
    12.   
    13.     public Form1()  
    14.     {  
    15.         InitializeComponent();  
    16.   
    17.         bkWorker.WorkerReportsProgress = true;  
    18.         bkWorker.WorkerSupportsCancellation = true;  
    19.         bkWorker.DoWork += new DoWorkEventHandler(DoWork);  
    20.         bkWorker.ProgressChanged += new ProgressChangedEventHandler(ProgessChanged);  
    21.         bkWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteWork);  
    22.     }  
    23.   
    24.     private void btnStart_Click(object sender, EventArgs e)  
    25.     {  
    26.         percentValue = 10;  
    27.         this.progressBar1.Maximum = 1000;  
    28.         // 执行后台操作  
    29.         bkWorker.RunWorkerAsync();  
    30.     }  
    31.   
    32.     public void DoWork(object sender, DoWorkEventArgs e)  
    33.     {  
    34.         // 事件处理,指定处理函数  
    35.         e.Result = ProcessProgress(bkWorker, e);  
    36.     }  
    37.   
    38.     public void ProgessChanged(object sender, ProgressChangedEventArgs e)  
    39.     {  
    40.         // bkWorker.ReportProgress 会调用到这里,此处可以进行自定义报告方式  
    41.         this.progressBar1.Value = e.ProgressPercentage;  
    42.         int percent = (int)(e.ProgressPercentage / percentValue);  
    43.         this.label1.Text = "处理进度:" + Convert.ToString(percent) + "%";  
    44.     }  
    45.   
    46.     public void CompleteWork(object sender, RunWorkerCompletedEventArgs e)  
    47.     {  
    48.         this.label1.Text = "处理完毕!";  
    49.     }  
    50.   
    51.     private int ProcessProgress(object sender, DoWorkEventArgs e)  
    52.     {  
    53.         for (int i = 0; i <= 1000; i++)  
    54.         {  
    55.             if (bkWorker.CancellationPending)  
    56.             {  
    57.                 e.Cancel = true;  
    58.                 return -1;  
    59.             }  
    60.             else  
    61.             {  
    62.                 // 状态报告  
    63.                 bkWorker.ReportProgress(i);  
    64.   
    65.                 // 等待,用于UI刷新界面,很重要  
    66.                 System.Threading.Thread.Sleep(1);  
    67.             }  
    68.         }  
    69.   
    70.         return -1;  
    71.     }  
    72. }  

    下面是运行结果

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

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

    子窗体代码

    [csharp] view plaincopy
     
    1. public partial class Form2 : Form  
    2.  {  
    3.      public Form2()  
    4.      {  
    5.          InitializeComponent();  
    6.      }  
    7.   
    8.      public void SetNotifyInfo(int percent, string message)  
    9.      {  
    10.          this.label1.Text = message;  
    11.          this.progressBar1.Value = percent;  
    12.      }  
    13.  }  

    下面是运行结果


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

    [csharp] view plaincopy
     
    1. public partial class Form1 : Form  
    2. {  
    3.     private Form2 progressForm = new Form2();  
    4.     // 代理定义,可以在Invoke时传入相应的参数  
    5.     private delegate void funHandle(int nValue);  
    6.     private funHandle myHandle = null;  
    7.   
    8.     public Form1()  
    9.     {  
    10.         InitializeComponent();  
    11.     }  
    12.   
    13.     private void btnStart_Click(object sender, EventArgs e)  
    14.     {  
    15.         // 启动线程  
    16.         System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(ThreadFun));  
    17.         thread.Start();  
    18.     }  
    19.   
    20.     /// <summary>  
    21.     /// 线程函数中调用的函数  
    22.     /// </summary>  
    23.     private void ShowProgressBar()  
    24.     {  
    25.         myHandle = new funHandle(progressForm.SetProgressValue);  
    26.         progressForm.ShowDialog();  
    27.     }  
    28.   
    29.     /// <summary>  
    30.     /// 线程函数,用于处理调用  
    31.     /// </summary>  
    32.     private void ThreadFun()  
    33.     {  
    34.         MethodInvoker mi = new MethodInvoker(ShowProgressBar);  
    35.         this.BeginInvoke(mi);  
    36.   
    37.         System.Threading.Thread.Sleep(1000); // sleep to show window  
    38.   
    39.         for (int i = 0; i < 1000; ++i)  
    40.         {  
    41.             System.Threading.Thread.Sleep(5);  
    42.             // 这里直接调用代理  
    43.             this.Invoke(this.myHandle, new object[] { (i / 10) });  
    44.         }  
    45.     }  
    46. }  

    子窗体代码

    [csharp] view plaincopy
     
    1. public partial class Form2 : Form  
    2. {  
    3.     public Form2()  
    4.     {  
    5.         InitializeComponent();  
    6.     }  
    7.   
    8.     public void SetProgressValue(int value)  
    9.     {  
    10.         this.progressBar1.Value = value;  
    11.         this.label1.Text = "Progress :" + value.ToString() + "%";  
    12.   
    13.         // 这里关闭,比较好,呵呵!  
    14.         if (value == this.progressBar1.Maximum - 1) this.Close();  
    15.     }  
    16. }  

    下面是运行结果图


    参考资料

    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 }

  • 相关阅读:
    Java8 Period.between方法坑及注意事项
    mybatis入门-第一个程序
    mybatis入门-框架原理
    初识servlet--未完成
    初识servlet
    session是什么
    session工作原理简介
    笔记本维修介绍
    j2se 总结
    maven
  • 原文地址:https://www.cnblogs.com/qinge/p/4402264.html
Copyright © 2020-2023  润新知