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#进度条实现源码
推荐阅读
- 记一次 .NET 某药品仓储管理系统 卡死分析
- IIS发布.net连接不上数据库解决办法
- 浅谈.NET 6 中 gRPC 的最新功能
- 利用Visual Studio 2017的扩展开发(VSIX、ItemTemplate) 快速实现项目的半自动化搭建
- .net|利用MSXML2.XMLHTTP的无刷新技术
- 配置VS2008中文版调试.netframework源代码
- .net|解决Win8.1下VS2005编辑报错的问题
- Java与C#间json时间格式互转完美解决方案
- 在VS.NET内使用“从源代码管理打开”时出现无法读取项目文件的错误