C#利用委托跨线程更新UI数据
转:http://www.2cto.com/kf/201206/136587.html
在使用C#的过程中,难免会用到多线程,而用多线程之后,线程如何与界面交互则是一个非常头疼的问题。其实不仅仅是界面,一般情况下,我们往往需要获得线程的一些信息来确定线程的状态。比较好的方式是用委托实现,看例子:
注:本例利用委托和跨线程访问技术,用界面上的两个label控件实时显示线程的执行次数。网上虽然有很多这方面的文章,但是过于简略,说明很少,刚刚接触这方面的程序员很难理解,故写此文。
TestClass类:
1. class TestClass
2. {
3. //声明一个delegate(委托)类型:testDelegate,该类型可以搭载返回值为空,参数只有一个(long型)的方法。
4. public delegate void testDelegate(long i);
5.
6. //声明一个testDelegate类型的对象。该对象代表了返回值为空,参数只有一个(long型)的方法。它可以搭载N个方法。
7. public testDelegate mainThread;
8.
9. /// <summary>
10. /// 测试方法
11. /// </summary>
12. public void testFunction()
13. {
14. long i = 0;
15. while(true)
16. {
17. i++;
18. mainThread(i); //调用委托对象
19. Thread.Sleep(1000); //线程等待1000毫秒
20. }
21. }
22. }
winform界面代码:
1. /// <summary>
2. /// 按钮单击事件
3. /// </summary>
4. /// <param name="sender"></param>
5. /// <param name="e"></param>
6. private void button1_Click(object sender, EventArgs e)
7. {
8. //创建TestClass类的对象
9. TestClass testclass = new TestClass();
10.
11. //在testclass对象的mainThread(委托)对象上搭载两个方法,在线程中调用mainThread对象时相当于调用了这两个方法。
12. testclass.mainThread = new TestClass.testDelegate(refreshLabMessage1);
13. testclass.mainThread += new TestClass.testDelegate(refreshLabMessage2);
14.
15. //创建一个无参数的线程,这个线程执行TestClass类中的testFunction方法。
16. Thread testclassThread = new Thread(new ThreadStart(testclass.testFunction));
17. //启动线程,启动之后线程才开始执行
18. testclassThread.Start();
19. }
20.
21. /// <summary>
22. /// 在界面上更新线程执行次数
23. /// </summary>
24. /// <param name="i"></param>
25. private void refreshLabMessage1(long i)
26. {
27. //判断该方法是否被主线程调用,也就是创建labMessage1控件的线程,当控件的InvokeRequired属性为ture时,说明是被主线程以外的线程调用。如果不加判断,会造成异常
28. if (this.labMessage1.InvokeRequired)
29. {
30. //再次创建一个TestClass类的对象
31. TestClass testclass = new TestClass();
32. //为新对象的mainThread对象搭载方法
33. testclass.mainThread = new TestClass.testDelegate(refreshLabMessage1);
34. //this指窗体,在这调用窗体的Invoke方法,也就是用窗体的创建线程来执行mainThread对象委托的方法,再加上需要的参数(i)
35. this.Invoke(testclass.mainThread,new object[] {i});
36. }
37. else
38. {
39. labMessage1.Text = i.ToString();
40. }
41. }
42.
43. /// <summary>
44. /// 在界面上更新线程执行次数
45. /// </summary>
46. /// <param name="i"></param>
47. private void refreshLabMessage2(long i)
48. {
49. //同上
50. if (this.labMessage2.InvokeRequired)
51. {
52. //再次创建一个TestClass类的对象
53. TestClass testclass = new TestClass();
54. //为新对象的mainThread对象搭载方法
55. testclass.mainThread = new TestClass.testDelegate(refreshLabMessage2);
56. //this指窗体,在这调用窗体的Invoke方法,也就是用窗体的创建线程来执行mainThread对象委托的方法,再加上需要的参数(i)
57. this.Invoke(testclass.mainThread, new object[] { i });
58. }
59. else
60. {
61. labMessage2.Text = i.ToString();
62. }
63. }
执行效果:

说明:
为了便于大家理解,我写了很详细的注释。在这还要说明一下,因为这里边有些“莫名其妙”的地方。
l 如何创建线程就不废话了,一看就懂。
l public delegate void testDelegate(long i);这句话是创建了一个委托,名字是testDelegate,指定了委托的类型,什么返回值啦、什么参数啦,可以把testDelegate理解为一个类,一个规范;publictestDelegate mainThread;这句话当然就是创建testDelegate类的对象了,真正搭载方法的是mainThread对象,它可以搭载N个方法,顺序执行。如何搭载捏?看这句话:testclass.mainThread= new TestClass.testDelegate(refreshLabMessage1);这句话是给testclass对象中的mainThread对象搭载方法,但是后边的new比较难以理解。大家都知道,new这个关键字就是用来创建对象的,刚刚已经提醒大家把委托看成一个类,因此这new的是testDelegate这个委托,而不是TestClass(一定要看清了,如果是new的TestClass,要在TestClass后加括号的,后边接的是方法,而testDelegate明显不是方法,因此会报错)。相当于是在TestClass类中又套了一个类,所以才会这样写。refreshLabMessage1当然就是testDelegate类构造方法的参数,用来指明委托哪个方法。最后把实例赋给同类型的mainThread。另外,在此例中mainThread委托了两个方法,用+=运算符即可,如果想去除某个方法,亦可用-=运算符。www.2cto.com
l 最后需要说明的就是跨线程访问控件问题。窗体上的控件只允许创建它们的线程访问,也就是主线程,如果非主线程访问则会发生异常。我们可以借助于控件的InvokeRequired属性来判断该控件目前是否被主线程访问,如果是,返回false。如果不是,再利用Invoke方法找到主线程,让主线程执行访问控件的方法,本例中借助于TestClass类中的mainThread对象,委托了访问控件的方法refreshLabMessage1,再把mainThread对象传入运行在主线程上的控件的Invoke方法即可。Invoke方法可以理解为:在哪个控件上调用了Invoke,就用那个控件所在的线程处理委托方法。在本例中用this调用Invoke方法,也就是窗体所在的线程,当然也是控件所在的线程。Invoke的两个参数分别是:委托、委托的方法需要的参数。
C#利用委托跨线程更新UI数据的更多相关文章
- [转]C#利用委托跨线程更新UI数据
在使用C#的过程中,难免会用到多线程,而用多线程之后,线程如何与界面交互则是一个非常头疼的问题.其实不仅仅是界面,一般情况下,我们往往需要获得线程的一些信息来确定线程的状态.比较好的方式是用委托实现, ...
- C# Winform 跨线程更新UI控件常用方法汇总(多线程访问UI控件)
概述 C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现“线程间操作无效: 从不是创建控件的线程访问它”的异常.处理跨线程更新Winform UI控件常用的方法有4种:1. ...
- C# Winform 跨线程更新UI控件常用方法总结(转)
出处:http://www.tuicool.com/articles/FNzURb 概述 C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现“线程间操作无效: 从不是创建控件 ...
- 简短总结一下C#里跨线程更新UI(转)
摘自: http://my.oschina.net/sdqxcxh/blog/53707 跨线程更新UI是写多线程程序尤其是通信类的程序经常遇到的问题,这里面主要的问题是冲突,比如数据线程想要更新UI ...
- (转).NET 4.5中使用Task.Run和Parallel.For()实现的C# Winform多线程任务及跨线程更新UI控件综合实例
http://2sharings.com/2014/net-4-5-task-run-parallel-for-winform-cross-multiple-threads-update-ui-dem ...
- 简短总结一下C#里跨线程更新UI
摘自: http://my.oschina.net/sdqxcxh/blog/53707 跨线程更新UI是写多线程程序尤其是通信类的程序经常遇到的问题,这里面主要的问题是冲突,比如数据线程想要更新UI ...
- C# 委托 / 跨线程访问UI / 线程间操作无效: 从不是创建控件“Form1”的线程访问它
C# 委托 / 跨线程访问UI / 线程间操作无效: 从不是创建控件“Form1”的线程访问它 网上的代码都比较复杂,还是这个简单 见代码, 简易解决办法: 主窗体代码 using System; ...
- Winform之跨线程更新UI
Winform之跨线程更新UI 使用`Invoke`或者`BeginInvoke`与UI线程交互示例 参考及源码 使用Invoke或者BeginInvoke与UI线程交互示例 private void ...
- C# 跨线程更新 UI
Winforms 跨线程更新 UI 在 Winforms 中, 所有的控件都包含 InvokeRequired 属性, 如果我们要更新UI,通过它我们可以判断是否需要调用 [Begin]Invoke. ...
随机推荐
- IOS 特定于设备的开发:监测Retina支持
近年来,Apple在其旗舰设备上引入了Retina显示屏.根据Apple的说法,他的像素密度非常高,足以使人眼无法区分单独的像素. UIScreen类提供了一种容易的方式,用于监查当前设备是否提供了内 ...
- hdoj 2620 Bone Collector(0-1背包)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2602 思路分析:该问题为经典的0-1背包问题:假设状态dp[i][v]表示前i件物品恰放入一个容量为v ...
- 三分钟教你学Git(十六) - 统计
有时候想统计仓库的情况,比方代码量.贡献者之类的. 1 统计某人的commit数量 git log --author="$(git config --get user.name)" ...
- SASS组件开发
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- objective-C学习笔记(四)函数成员:方法(函数)
函数分为: 全局函数(C语言函数) 成员函数(OBJC方法):实例方法 “-” 和类方法“+”的区别 //这里要区别静态变量(类变量).全局函数.常量的区别 OBJC里面,所有方法默认为公有方法.没 ...
- jira使用
JIRA的生产者把JIRA定义为Professional Issue Tracker,即它是一个专业的问题跟踪管理的软件.这里的"问题"对应的英文单词是Issue,所以含义比较广, ...
- solr6环境搭建
1.下载并安装jdk1.8,配置环境变量 2.下载并安装tomcat8(8以上) 3.下载solr源码,转变部署solr a)[solr-6.2.0\server\solr-webapp]下的weba ...
- windows server2008 r2修改远程桌面连接端口。
1. windows 2008远程桌面端口默认是用的是3389端口,但是由于安全考虑,通常我们安装好系统后一般都会考虑把原来的3389端口更改为另外的端口. 2.更改过程: 2-1.打开注册表: ...
- 织梦dedecms|文章页通用标签
当前位置: {dede:field name='position'/}上一页: {dede:prenext get='pre'/}下一页: {dede:prenext get='next'/}收 ...
- javaScript中有关正则表达式的用法总结
js中处理正则表达式的类:RegExp 用法: var reg=new RegExp("express"); 或者: var reg=/express/; js中常用的6个方法: ...