C#Invoke委托在多线程中的使用
Posted 无声蝉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#Invoke委托在多线程中的使用相关的知识,希望对你有一定的参考价值。
一步一步跟随着我的脚步看一看
Form上我设置一个button,text属性为“点击开始测试”;现在我想点击它以后,动态变化从1~10赋值
(1)
第一个映入脑中的方式就是这样写
private void button1_Click(object sender, EventArgs e)
button1.Enabled = false;
for(int i=1;i<10;i++)
button1.Text = i.ToString();
Thread.Sleep(1000);
button1.Text = "点击开始测试";
button1.Enabled = true;
有没有问题?肯定有的啦,我点击以后,界面倒是disable了,但是没有1~10出现,时间一到,恢复enable。为什么呢?
原因:直接主线程休眠是达不到效果的,此时桌面还处于假死状态,更新不了text值。代码放在了UI线程执行,阻塞了UI的显示,所以中间的结果你看不到。实验了两种方式解决:
- 在Thread.Sleep(1000);后加 button1.Refresh();
- 在Thread.Sleep(1000);后加 Application.DoEvents();
(2)
既然是由于代码放在了UI线程,那我新建个线程,在那里面更新UI控件好了。
private void button1_Click(object sender, EventArgs e)
//启动一个线程
new Thread(ThreadTask).Start();
//线程函数
public void ThreadTask()
button1.Enabled = false;
for (int i = 0; i < 10; i++)
button1.Text = i.ToString();
Thread.Sleep(1000);
button1.Text = "点击开始测试";
button1.Enabled = true;
出错了!!!
造成这种异常的原因在于,控件是在主线程中创建的(比如this.Controls.Add(...);),进入控件的事件响应函数时,是在控件所在的线程,并不是主线程。在控件的事件响应函数中改变控件的状态,可能与主线程发生线程冲突。如果主线程正在重绘控件外观,此时在别的线程改变控件外观,就会造成画面混乱。
(3)
下面该主角出场了,C#的委托机制,由于历史的原因,有这么几种形式:
//第一种
button1.Invoke(new EventHandler(delegatebutton1.Text = "关闭";));
//第二种
this.Invoke(new EventHandler(delegatebutton1.Text = "关闭";));
//第三种 网上说自C# 3.0开始就有了
this.Invoke(new Action(() => button1.Text = "关闭";));
我喜欢用第三种,好记,哈哈。好了,接下来实现以下吧!
private void button1_Click(object sender, EventArgs e)
//启动一个线程
new Thread(ThreadTask).Start();
//线程函数
public void ThreadTask()
//首先将button对象禁用
this.Invoke(new Action(() =>
button1.Enabled = false;
));
for (int i = 0; i < 10; i++)
this.Invoke(new Action(() =>
button1.Text = i.ToString();
));
Thread.Sleep(1000);
//虽然不是循环内,请不要忘记,你的调用依然在辅助线程中,所以,还是需要invoke的。
//还原状态,设置按钮的文本为初始状态,设置按钮可用。
this.Invoke(new Action(() =>
button1.Text = "点击开始测试";
button1.Enabled = true;
));
大功告成喽!!
以上是关于C#Invoke委托在多线程中的使用的主要内容,如果未能解决你的问题,请参考以下文章