为什么需要进度条?
这里有200个左右的文件,每个文件里面有1000条数据库插入语句,总共约200 000条记录。
在单线程情况下,执行插入时界面会失去响应,完成插入需要长达8个小时。
不会有人认为界面没有卡死,即使是我自己写的程序,也不禁怀疑是否程序卡死。
进度条,以及各种执行情况显示,在这种情况下真的很重要。
我还不明白为什么界面不能刷新,即使改变控件位置等等,因此目前只能采用多线程的方式实现进度条。
方式一
选择控件
一个Button及ProgressBar
实现思路
由UI线程负责画面刷新,另一个线程负责计算
窗体的字段this.count就是返回给进度条的数据
public partial class Form1 : Form { int count = 0;
这是模拟计算的函数,当然方法体也可以替换为实际的操作。
public void progress()//模拟执行一项耗时的操作 { bool add = true;//进度条增长 while (true) { while (add) { if (this.count == 10000)//进度条上限 { add = false; break; } this.count += 100;//要操作的数据 Thread.Sleep(100); } while (!add) { if (this.count == 0)//进度条下限 { add = true; break; } this.count -= 100; Thread.Sleep(100); } } }
在Button的点击事件中,将这个函数传递给线程
private void button1_Click(object sender, EventArgs e) { Thread t = new Thread(new ThreadStart(progress)); t.IsBackground = true;//在主界面关闭时此线程销毁 t.Start(); }
此时点击按钮,this.count变化,但ProgressBar的Value没变,要使Value变化,得不停的给Value赋值,因此增加一个Timer
private void timer1_Tick(object sender, EventArgs e) { this.progressBar1.Value = this.count; }
现在已经实现了进度条,并且由于是单独的线程执行计算,界面并不会失去响应,任然是可互动的
结果
方式二
使用委托,将progress()传递给委托,另定义call方法,使用invoke方法解决调用线程无法访问此对象的问题
public delegate void Draw(); Draw draw; private void button1_Click(object sender, EventArgs e) { draw = new Draw(progress);//在使用Invoke时才需要委托 //Control.CheckForIllegalCrossThreadCalls = false; Thread t = new Thread(new ThreadStart(call)); //Thread t = new Thread(new ThreadStart(progress)); t.IsBackground = true;//在主界面关闭时此线程销毁 t.Start(); } public void call() { while (true) { progressBar1.Invoke(draw);//似乎是提交给UI线程运行,UI线程在执行完自己代码后才会执行Invoke提交的代码 } }
invoke方法虽然是在新创建的线程中调用的,但根据网上一些资料以及我自己的实验,invoke应当还是由UI线程在执行,也就是说progress()由UI线程在执行,并没有解决计算与更新分离的问题,虽然这是网上大部分资料的方式
而且这种方法界面虽然更新,但是没有响应
改写progress()
public void progress()//模拟执行一项耗时的操作 { bool add = true;//进度条增长 while (true) { while (add) { if (this.count == 10000) { add = false; break; } this.count += 100; this.progressBar1.Value = this.count;//此处新增 Thread.Sleep(100); } while (!add) { if (this.count == 0) { add = true; break; } this.count -= 100; this.progressBar1.Value = this.count;//此处新增 Thread.Sleep(100); } } }
停止使用Timer
结果
虽然实现了进度条,但是与界面不能互动,窗体处于无响应状态