C# 跨线程调用控件的4中方法
在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应。 同时我们又需要在工作线程中更新UI界面上的控件,
下面介绍几种常用的方法
阅读目录
- 线程间操作无效
- 第一种办法:禁止编译器对跨线程访问做检查
- 第二种办法: 使用delegate和invoke来从其他线程中调用控件
- 第三种办法: 使用delegate和BeginInvoke来从其他线程中控制控件
- 第四种办法: 使用BackgroundWorker组件
- 源代码下载
线程间操作无效
界面上有一个button和一个label, 点击button会启动一个线程来更新Label的值


private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel));
thread1.Start("更新Label");
}</span><span style="color:rgb(0,0,255); line-height:1.5!important">private</span> <span style="color:rgb(0,0,255); line-height:1.5!important">void</span> UpdateLabel(<span style="color:rgb(0,0,255); line-height:1.5!important">object</span><span style="line-height:1.5!important"> str)
{
</span><span style="color:rgb(0,0,255); line-height:1.5!important">this</span>.label1.Text =<span style="line-height:1.5!important"> str.ToString();
}</span></pre>
运行后, 程序会报错 "跨线程操作无效,从不是创建"label1"的线程访问它"

这是因为.NET禁止了跨线程调用控件, 否则谁都可以操作控件,最后可能造成错误。
下面介绍几种跨线程调用控件的方法
第一种办法:禁止编译器对跨线程访问做检查
这是最简单的办法, 相当于不检查线程之间的冲突,允许各个线程随便乱搞,最后Lable1控件的值是什么就难以预料了 (不推荐使用这种方法)
public Form1()
{
InitializeComponent();
// 加入这行
Control.CheckForIllegalCrossThreadCalls = false;
}
第二种办法: 使用delegate和invoke来从其他线程中调用控件
调用控件的invoke方法,就可以控制控件了,例如


private void button2_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel2));
thread1.Start("更新Label");
}</span><span style="color:rgb(0,0,255); line-height:1.5!important">private</span> <span style="color:rgb(0,0,255); line-height:1.5!important">void</span> UpdateLabel2(<span style="color:rgb(0,0,255); line-height:1.5!important">object</span><span style="line-height:1.5!important"> str)
{
</span><span style="color:rgb(0,0,255); line-height:1.5!important">if</span><span style="line-height:1.5!important"> (label2.InvokeRequired)
{
</span><span style="color:rgb(0,128,0); line-height:1.5!important">//</span><span style="color:rgb(0,128,0); line-height:1.5!important"> 当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它</span>
Action<<span style="color:rgb(0,0,255); line-height:1.5!important">string</span>> actionDelegate = (x) => { <span style="color:rgb(0,0,255); line-height:1.5!important">this</span>.label2.Text =<span style="line-height:1.5!important"> x.ToString(); };
</span><span style="color:rgb(0,128,0); line-height:1.5!important">//</span><span style="color:rgb(0,128,0); line-height:1.5!important"> 或者
</span><span style="color:rgb(0,128,0); line-height:1.5!important">//</span><span style="color:rgb(0,128,0); line-height:1.5!important"> Action<string> actionDelegate = delegate(string txt) { this.label2.Text = txt; };</span>
<span style="color:rgb(0,0,255); line-height:1.5!important">this</span><span style="line-height:1.5!important">.label2.Invoke(actionDelegate, str);
}
</span><span style="color:rgb(0,0,255); line-height:1.5!important">else</span><span style="line-height:1.5!important">
{
</span><span style="color:rgb(0,0,255); line-height:1.5!important">this</span>.label2.Text =<span style="line-height:1.5!important"> str.ToString();
}
}</span></pre>
第三种办法: 使用delegate和BeginInvoke来从其他线程中控制控件
只要把上面的 this.label2.Invoke(actionDelegate, str); 中的 Invoke 改为BeginInvoke方法就可以了
Invoke方法和BeginInvoke方法的区别是
Invoke方法是同步的, 它会等待工作线程完成,
BeginInvoke方法是异步的, 它会另起一个线程去完成工作线程
第四种办法: 使用BackgroundWorker组件(推荐使用这个方法)
BackgroundWorker是.NET里面用来执行多线程任务的控件,它允许编程者在一个单独的线程上执行一些操作。耗时的操作(如下载和数据库事务)。用法简单


private void button4_Click(object sender, EventArgs e)
{
using (BackgroundWorker bw = new BackgroundWorker())
{
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync("Tank");
}
}</span><span style="color:rgb(0,0,255); line-height:1.5!important">void</span> bw_DoWork(<span style="color:rgb(0,0,255); line-height:1.5!important">object</span><span style="line-height:1.5!important"> sender, DoWorkEventArgs e)
{
</span><span style="color:rgb(0,128,0); line-height:1.5!important">//</span><span style="color:rgb(0,128,0); line-height:1.5!important"> 这里是后台线程, 是在另一个线程上完成的
</span><span style="color:rgb(0,128,0); line-height:1.5!important">//</span><span style="color:rgb(0,128,0); line-height:1.5!important"> 这里是真正做事的工作线程
</span><span style="color:rgb(0,128,0); line-height:1.5!important">//</span><span style="color:rgb(0,128,0); line-height:1.5!important"> 可以在这里做一些费时的,复杂的操作</span>
Thread.Sleep(<span style="color:rgb(128,0,128); line-height:1.5!important">5000</span><span style="line-height:1.5!important">);
e.Result </span>= e.Argument + <span style="color:rgb(128,0,0); line-height:1.5!important">"</span><span style="color:rgb(128,0,0); line-height:1.5!important">工作线程完成</span><span style="color:rgb(128,0,0); line-height:1.5!important">"</span><span style="line-height:1.5!important">;
} </span><span style="color:rgb(0,0,255); line-height:1.5!important">void</span> bw_RunWorkerCompleted(<span style="color:rgb(0,0,255); line-height:1.5!important">object</span><span style="line-height:1.5!important"> sender, RunWorkerCompletedEventArgs e)
{
</span><span style="color:rgb(0,128,0); line-height:1.5!important">//</span><span style="color:rgb(0,128,0); line-height:1.5!important">这时后台线程已经完成,并返回了主线程,所以可以直接使用UI控件了 </span>
<span style="color:rgb(0,0,255); line-height:1.5!important">this</span>.label4.Text =<span style="line-height:1.5!important"> e.Result.ToString();
}</span></pre>
转自https://www.cnblogs.com/lonelyxmas/p/4097737.html
C# 跨线程调用控件的4中方法的更多相关文章
- C# 跨线程调用控件
在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应. 同时我们又需要在工作线程中更新UI界面上的控件, 下面介绍几种常用的方法 阅读目录 线程间操作无效 第一种办法:禁 ...
- 【转载】C# 跨线程调用控件
转自:http://www.cnblogs.com/TankXiao/p/3348292.html 感谢原作者,转载以备后用 在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停 ...
- 跨线程调用控件之MethodInvoker
原文:http://www.cnblogs.com/cm8448940/archive/2008/07/10/1240045.html 使用到两个控件,一个按钮button1,一个标签label1. ...
- WinForm与WPF下跨线程调用控件
Winform下: public delegate void UpadataTextCallBack(string str,TextBox text); public void UpadtaText( ...
- winform 跨线程 调用控件
public delegate void rtbCallBack(string txt); public void rtbAddText(string txt) { if (this.rtb.Invo ...
- C#跨线程操作控件的最简单实现探究
随着程序复杂度的提高,程序不可避免会出现多个线程,此时就很可能存在跨线程操作控件的问题. 跨线程操作UI控件主要有三类方式: 1.禁止系统的线程间操作检查.(此法不建议使用) 2.使用Invoke(同 ...
- C# 关于跨线程访问控件问题
跨线程访问控件问题的原因是:控件都是在主线程中创建的,而系统默认控件的修改权归其创建线程所有.在子线程中如果需要直接修改控件的内容,需要使用委托机制将控件的修改操作交给主线程处理.因此,当没有使用委托 ...
- 在.Net中进行跨线程的控件操作(下篇:BackgroundWorker)
在.Net中,如果我们在非UI线程上访问窗体上的控件的时候,会产生一个跨线程调用的异常,那么如何处理这种情况呢?在上一章中,我介绍了使用Control.Invoke方法,如果你不习惯使用委托,那么.N ...
- c# winform InvokeRequired 解决跨线程访问控件
C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它. Windows 窗体中 ...
随机推荐
- 树——sum-root-to-leaf-numbers(根到叶节点数字之和)
问题: Given a binary tree containing digits from0-9only, each root-to-leaf path could represent a numb ...
- chattr 改变文件的扩展属性
1. 命令功能 chattr和lsattr用来改变文件.目录属性和查看这种文件属性:chmod只是改变文件的读.写.执行权限,更底层的属性控制是由chattr来改变. 2. 语法格式 chattr [ ...
- Jmeter接口测试---加解密
1.加解密的jar包放到jmeter的lib/ext目录下. 项目打jar包参考https://www.cnblogs.com/fulucky/p/9436229.html 2.在测试计划---> ...
- Java List 类型转换
java的类型转换让人忍不住在开始编码前骂一声 FUCK! 1 子类转父类 up List<SubClass> subs = ...; List<? extends BaseCl ...
- Synchronized锁升级
Synchronized锁升级 锁的4中状态:无锁状态.偏向锁状态.轻量级锁状态.重量级锁状态(级别从低到高) 为什么要引入偏向锁? 因为经过HotSpot的作者大量的研究发现,大多数时候是不存在锁竞 ...
- Python---基础----数据类型的内置函数(主要介绍字符串、列表、元组、字典、集合的内置函数)(二)
2019-05-24 -------------------------------- 一. # splitlines() 以换行切割字符串s = '''日照香炉生紫烟\n疑是银河落九天\n飞流 ...
- php array_combine()函数 语法
php array_combine()函数 语法 作用:通过合并两个数组来创建一个新数组,其中的一个数组是键名,另一个数组的值为键值.dd马达价格 语法:array_combine(keys,valu ...
- 最大独立点集&最小点覆盖
1.最大独立点集: 在二分图中,选最多的点,使得任意两个点之间没有直接边连接. 最大独立集= 最小边覆盖 = 总点数- 最大匹配 (条件:在二分图中) 2.最小边覆盖: 在二分图中,求最少的边,使得他 ...
- [CSP-S模拟测试]:回文(hash+二维前缀和)
题目描述 闲着无聊的$YGH$秒掉上面两道题之后,开始思考有趣的回文串问题了. 他面前就有一个漂浮着的字符串.显然$YGH$是会$manacher$的,于是他随手求出了这个字符串的回文子串个数.但是他 ...
- vue.jsc初体验
Vue 1.安装脚手架 (1)npm install -g vue-cli (2)Vue -v //查看是否安装成功 (3)Vue init webpack name(名称) (4)Npm insta ...