解决c# progressBar更新出现界面假死
最近一个项目需求中的一个功能是需要用progressBar反映处理文件的进度。
研究了Invoke和BeginInvoke方法。
Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线程上执行指定的委托。
Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄所在线程上异步执行指定委托。
我开始的想法是开一个线程处理,代码如下:
private delegate void DoDataDelegate(object number);
private void button2_Click(object sender, EventArgs e)
{
// Thread myThread = new Thread(DoData);
Thread myThread = new Thread(new ParameterizedThreadStart(DoData));
myThread.IsBackground = true;
myThread.Start(int.Parse(textBox1.Text)); //线程开始
Console.WriteLine("主线程继续执行---------------");
}
private void DoData(object number)
{
if (progressBar1.InvokeRequired)
{
Console.WriteLine("开始");
DoDataDelegate d = DoData;
progressBar1.BeginInvoke(d, number);
//代码段D
}
else
{
progressBar1.Maximum = (int)number;
Console.WriteLine("准备进行循环调用");
for (int i = 0; i < (int)number; i++)
{
//这里是一段耗时长的代码
progressBar1.Value = i + 1;
} }
}
在上述代码中当执行到progressBar1.BeginInvoke(d, number);时,myThread封送消息给UI,然后自己继续执行代码段D,代码段D的执行相对于myThread是异步的。如果将
progressBar1.BeginInvoke(d, number);换成progressBar1.Invoke(d, number);其余的代码不变,那么代码段D将会等到线程myThread结束后才会执行。无论是调用BeginInvoke或者Invoke,因为调用者是progressBar1,所以更新progressBar1.Value时,是在"拥有此控件的基础窗口句柄的线程(UI线程)上执行指定的委托",在更新value值之前有一段耗时长的代码,所以此时UI线程会阻塞,处于假死状态。
我的解决办法是使用BackgroundWorker 类。
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += DoWork_Handler;
backgroundWorker1.ProgressChanged += ProgressChanged_Handler;
private void button2_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
//这里省略一段执行耗时的操作
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
// Change the value of the ProgressBar to the BackgroundWorker progress.
progressBar1.Value = e.ProgressPercentage;
}
BackgroundWorker.RunWorkerAsync是创建了一个线程处理耗时的操作,backgroundWorker1_DoWork方法执行,执行到backgroundWorker1.ReportProgress(i);会触发backgroundWorker1_ProgressChanged方法的执行,在backgroundWorker1_ProgressChanged方法中,更新value的值。这样做UI界面和线程处理好使的工作是异步的,所以不会造成UI界面卡死的现象。
我了解了Invoke 和BeginInvoke的原理,但不知道怎么用他们实现更新ProgressBar的值,并保证UI界面不出现假死。所以我选择了BackgroundWorker解决了我的问题。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
再次更新。
经过和老师的讨论,我自己进行了实践。如果用ProgressBar反映处理耗时的程序的进度。可以开一个子线程处理耗时的部分,然后设置一个全局变量标识耗时的程序处理的进度。
代码段简化如下:
int num=0;
int number=16;
private void button2_Click(object sender, EventArgs e)
{
progressBar1.Maximum = number;
// Thread myThread = new Thread(DoData);
Thread myThread = new Thread(new ParameterizedThreadStart(DoData));
myThread.IsBackground = true;
myThread.Start(number); //线程开始 }
private void DoData(object number)
{
Console.WriteLine("准备进行循环调用");
for (int i = 0; i < (int)number; i++)
{
//这里是一段耗时长的代码 num = i + 1;
} }
}
然后加入一个Timer每隔一定的时间访问num的值。在Timer_tick函数中更新progressBar的value的值。
补充:在C#中的子线程中不能直接更新UI中的控件值。可以通过
1.Invoke或者BeginInvoke的方式调用委托的方法
2.使用BackGroundWorker类取代Thread类进行异步操作
3.通过设置窗体属性,取消线程安全检查来“避免跨线程操作异常”。(非线程安全,不建议使用)
4.通过UI线程的SynchronizationContext的Post/Send方法更新。
解决c# progressBar更新出现界面假死的更多相关文章
- C# Winform 窗体界面”假死”后台线程阻塞 解决办法–BeginInvoke
原文:C# Winform 窗体界面"假死"后台线程阻塞 解决办法–BeginInvoke 这个方法可以用在任何后台任务耗时较长,造成界面“假死”界面控件不更新的情况. 比如要要执 ...
- WinForm查询大数据界面假死,使用异步调用解决
用DataGridView无分页绑定一个几千条数据的查询,查询的时候界面直接卡死十几秒,用户体验非常不好,因此用异步操作解决界面卡死的问题原本场景:点击[查询]后,界面直接卡死优化场景:点击[查询]后 ...
- WinForm程序界面假死,寻求完美解决方案
故事的开端是这样的,小白是一个程序员,他确实也是一个小白,目前还在程序员发展的道路上,兢兢业业的小心求学. 有一天,小白接到一个任务,完成一个Winform程序,附加一个功能就是可以读IC卡. 小白终 ...
- C#中异步及winform中界面假死
c#中可以用BeginInvoke去启动异步调用,但是有两个BeginInvoke一个是controller的BeginInvoke还有一个是委托的BeginInvoke. 主要区别是controll ...
- Qt多线程和GUI界面假死(run()是线程的入口,就像main()对于应用程序的作用。分析QThread::exec函数的源码,旧的QMutexLocker模式其实很好用,挡住别人进入抢占资源,可照抄)good
QThread的常见特性: run()是线程的入口,就像main()对于应用程序的作用.QThread中对run()的默认实现调用了exec(),从而创建一个QEventLoop对象,由其处理该线程事 ...
- 使用publisher模式控制频繁的UI输出,避免Winform界面假死
http://www.cnblogs.com/Charltsing/p/publisher.html 最近测试task并发任务的效率与线程池的区别,发现了另外一个问题.task建立任务的速度很快,输出 ...
- WPF界面假死
首先要检查那些滥用 Timer.Dispacher Timer 或者滥用什么“线程+死循环+阻塞”轮询的代码. 这种是编程大忌,有些人不会设计事件驱动程序,而是滥用轮询. 若是:触发事件后的假死,搜W ...
- WinForm多线程及委托防止界面假死
当有大量数据需要计算.显示在界面或者调用sleep函数时,容易导致界面卡死,可以采用多线程加委托的方法解决. using System; using System.Collections.Generi ...
- 采用多线程方式,解决由于查询等待造成winfrom假死问题
1.这里是触发一个比较耗时的操作,比如一次大数据量的查询: Thread thread = new Thread(new ThreadStart(DoWord)); thread.Start(); 2 ...
随机推荐
- 用Java实现AES加密
参考内容来自:http://blog.csdn.net/hbcui1984/article/details/5201247 一)什么是AES? 高级加密标准(英语:Advanced Encryptio ...
- Spark环境搭建(四)-----------数据仓库Hive环境搭建
Hive产生背景 1)MapReduce的编程不便,需通过Java语言等编写程序 2) HDFS上的文缺失Schema(在数据库中的表名列名等),方便开发者通过SQL的方式处理结构化的数据,而不需要J ...
- CSS3 box-sizing的作用
设置CSS盒模型为标准模型或IE模型.标准模型的宽度只包括content,二IE模型包括border和padding box-sizing属性可以为三个值之一: content-box,默认值,bor ...
- css 制作圆角、圆形图形布局
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- windbg源码驱动调试 + 无源码驱动调试
windbg源码驱动调试 环境信息 虚拟机:win7 32位 windbg:6.12(版本不存在太大影响) 设置过程 windbg与虚拟机连接:链接 配置windbg 配置好双机调试后,点击win ...
- js高级1
1.每一个元素身上的事件都是天生自带的,不需要我们去定义,只需要我们给这个事件绑定的方法,当事件触发的时候就会执行这个方法. 2.事件绑定的方法 1,div.onclick=function(){} ...
- DTcms 模版用vs2015或2017 打开编辑时候 粘贴出问题 代码被调整
因为模版语言不是标准的HTML格式 ,所以HTML粘帖的时候会格式化 导致原标签出问题,这里修改下就可以了
- java_基础_类加载
类加载:Java命令的作用是启动虚拟机,虚拟机通过输入流,从磁盘上将字节码文件(.class文件)中的内容读入虚拟机,并保存起来的过程就是类加载. 类加载特性 : *在虚拟机的生命周期中一个 ...
- 关于word粘贴图片无法显示的原因
今天在进行word文档粘贴图片编辑操作的时候,老是无法完整的显示图片.或者干脆就不显示图片,以为是qq截图的图片格式无法粘贴到word文档里面,用Photoshop更改图片的格式仍然无法显示(将png ...
- Mac苹果电脑没有声音怎么办
有时候 Mac 从睡眠状态恢复之后没有声音,这是 Mac OS X 系统的一个 Bug.这是因为 Mac OS X 的核心音频守护进程「coreaudiod」出了问题,虽然简单的重启电脑就能解决,但是 ...