C#进度条实现

C#进度条实现 写在开头 记得本科大二时,和老师一起做项目,那时候刚接触编程没多久,技术很烂,当时有个功能是把shapfile文件中的属性表导出至本地Excel(*xls)格式,就想着能不能做个进度条,提高一下用户体验,于是乎,就兴奋的往窗口上拖个进度条(这个最擅长),然后各种捯饬,后来终于实现了,但是发现只有当表的记录较少时,进度条才能实时更新,否则记录很多时,进度条一直不更新,直至导出完成后进度条直接满血,当时很惆怅,百度了、谷歌了,得知这叫“UI阻塞”必须另开线程才能解决,这下我更惆怅了,那时的我“闻线程色变”,这种“黑技术”我做不到啊!!!
概述

  • 实现效果,点击按钮弹出进度条窗口,并开始执行任务,在进度条及文本标签中更新任务进度,关闭进度窗口时可终止任务
  • 实现技术,多线程(主线程更新UI,子线程处理耗时任务),委托
代码实现
  • 定义委托,限定进度回调函数接口
namespace Progress { public delegate void SetProgressValueEventHandler(int pos); //设置进度值的委托 定义参数列表 }

  • MainFrm类:主界面,用于启动任务子线程,并开启进度窗口;
namespace Progress { public partial class MainFrm : Form { public event SetProgressValueEventHandler SetProgressValueEvent; //定义事件用于回调 public Thread ProcessThread //定义子线程用于处理耗时任务 { get; set; }public MainFrm() { InitializeComponent(); }private void button1_Click(object sender, EventArgs e) { ProcessThread = new Thread(new ThreadStart(HandleThread)); //子线程初始化 ProgressFrm pFrm = new ProgressFrm(this); ProcessThread.Start(); //开启线程 pFrm.Show(); }private void HandleThread()//线程处理函数,实现耗时任务 { Run run = new Run(); run.RunProgress(150, SetProgressValueEvent); } } }

  • Run类:耗时任务实现类,实现耗时任务的逻辑代码;
class Run { public void RunProgress(int range, SetProgressValueEventHandler setProgressBar) { try { for (int i = 0; i < range; i++) { Thread.Sleep(100); //int p = 10 / (i - 10); //此处为了验证程序错误响应处理,当i=10时触发异常 setProgressBar(i * 100 / range); } setProgressBar(100); //耗时任务结束,进度条达到100; } catch (System.Exception ex) { System.Console.WriteLine(ex.Message); setProgressBar(101); //处理任务失败,向进度窗口传递消息传递值大于100或小于0的数 } } }

  • ProgressFrm类:进度控制窗口,用于显示进度。
namespace Progress { public partial class ProgressFrm : Form { private MainFrm mFrm; public ProgressFrm(MainFrm mFrm) { InitializeComponent(); this.mFrm = mFrm; //绑定事件处理函数 mFrm.SetProgressValueEvent += new SetProgressValueEventHandler(OnProgressValueChanged); } private void OnProgressValueChanged(int pos)//事件处理函数,设置进度条和进度值 { SetProgressBarValueInvoke(pos); SetProgressLabelValueInvoke(pos); }private void SetProgressBarValueInvoke(int pos)//跨线程调用 { if (progressBar.InvokeRequired) { SetProgressValueEventHandler setProgress = new SetProgressValueEventHandler(SetProgressBarValue); progressBar.Invoke(setProgress, new object[] { pos }); } else { SetProgressBarValue(pos); } } private void SetProgressBarValue(int pos) { //this.progressBar.Value = https://www.it610.com/article/pos; if (pos <= progressBar.Maximum && pos>= 0) { this.progressBar.Value = https://www.it610.com/article/pos; } }private void SetProgressLabelValueInvoke(int pos)//跨线程调用 { if (label.InvokeRequired) { SetProgressValueEventHandler setProgressLabel = new SetProgressValueEventHandler(SetProgressLabelValue); progressBar.Invoke(setProgressLabel, new object[] { pos }); } else { SetProgressBarLabelvalue(pos); } } private void SetProgressLabelValue(int pos) { if (pos <= progressBar.Maximum && pos>=0) { if (pos == progressBar.Maximum) { MessageBox.Show("处理成功···", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); this.Close(); } else { this.label.Text = pos.ToString() + "%"; } } else { MessageBox.Show("处理失败···", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); this.Close(); }}private void ProgressFrm_FormClosing(object sender, FormClosingEventArgs e) { try { mFrm.SetProgressValueEvent -= new SetProgressValueEventHandler(OnProgressValueChanged); mFrm.ProcessThread.Abort(); } catch (System.Exception ex) {} } } }

总结 现在读研,项目需要C#不常用了,但我想说虽然C#的语法比C++要容易很多(这竟然成为很多人对C#口诛笔伐的缘由),之所以容易而是微软把太多东西封装了,语法虽易但其中确蕴含了更深刻的思想。
封装意味着抽象,意味着更多需要理解的哲学思想。——室友(姜哥)
【C#进度条实现】对于我来说的便是委托/事件对C++函数指针的封装,研究了很久才算理解。
**能力有限请批评指正**
下载地址 C#进度条实现源码

    推荐阅读