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 窗体中 ...
随机推荐
- 基于TMS320C6678、FPGA XC5VLX110T的6U CPCI 8路光纤信号处理卡
基于TMS320C6678.FPGA XC5VLX110T的6U CPCI 8路光纤信号处理卡 1.板卡概述 本板卡由我公司自主研发,基于CPCI架构,符合CPCI2.0标准,采用两片TI DSP T ...
- 【LeetCode】前缀树 trie(共14题)
[208]Implement Trie (Prefix Tree) (2018年11月27日) 实现基本的 trie 树,包括 insert, search, startWith 操作等 api. 题 ...
- .iml文件恢复
基于maven的java工程 执行 mvn idea:module可恢复.iml文件
- bzoj5084 hashit 广义SAM+树链的并
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5084 题解 考虑平常对于静态问题,我们应该如何用 SAM 求本质不同的子串个数. 对于一个常规 ...
- IDEA git 合并多个commit
当前三个commit,demo1,demo2,demo3 选择demo1右键 选择action 跟着指示操作,最后合并 时间线: Log 框时间线:是从上到下,越来越早. 弹出框时间线:是从上到下,越 ...
- xcode7 添加个人账户 is not on any development teams
XCODE7已经可以免费真机测试, 但添加个人账户后,显示 is not on any development teams , 解决办法: 点击 “-” 删除当前账户,退出XCODE重新打开再添加即可 ...
- Axios 安卓4.4不兼容的问题
问题:Vue在使用Axios做接口请求时,如果是安卓4.4系统会发生报错,原因是安卓4.4不支持ES6的Promise语法 解决方案: 1.安装: npm install babel-polyfill ...
- K短路模板POJ 2449 Remmarguts' Date
Time Limit: 4000MS Memory Limit: 65536K Total Submissions:32863 Accepted: 8953 Description &qu ...
- div 上禁止复制的css实现方法
div { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-se ...
- pytest相关问题解析
1. 如果你想查询在你的环境下有哪些pytest的active plugin可以使用: py.test --traceconfig 会得到一个扩展的头文件名显示激活的插件和他们的名字.同时也会打印出当 ...