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 窗体中 ...
随机推荐
- Express 中配置使用 art-template模板引擎
art-template 官网 https://aui.github.io/art-template/ 安装: npm install --save art-template npm install ...
- Codeforces Round #340 (Div. 2) E. XOR and Favorite Number (莫队)
题目链接:http://codeforces.com/contest/617/problem/E 题目大意:有n个数和m次查询,每次查询区间[l, r]问满足ai ^ ai+1 ^ ... ^ aj ...
- 什么是shader?
一.什么是shader? shader是一段GLSL(openGL着色语言)小程序,运行在GPU(图形处理器),而非CPU使用GLSL语言编写,看上去像c或c++,但却是另外一种不同的语言.使用sha ...
- 2018-10-16-weekly
Algorithm 判断子序列 What 给定字符串 s 和 t ,判断 s 是否为 t 的子序列.如,"ace"是"abcde"的一个子序列,而"a ...
- bzoj5118 Fib数列2 二次剩余+矩阵快速幂
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5118 题解 这个题一看就是不可做的样子. 求斐波那契数列的第 \(n\) 项,\(n \leq ...
- Nginx-常用命令和配置文件
Nginx常用命令 1.启动命令 在/usr/local/nginx/sbin 目录下执行 ./nginx 2.关闭命令 在/usr/local/nginx/sbin 目录下执行 ./nginx s ...
- jsp选择文件夹上传
文件夹数据库处理逻辑 publicclass DbFolder { JSONObject root; public DbFolder() { this.root = new JSONObject(); ...
- 小A与最大子段和 斜率优化 + 二分 + 细节
Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) ...
- KMP字符串匹配模板
题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next. (如果你不知道这是什么意思也不要问,去百度 ...
- 2019 年百度之星·程序设计大赛 - 复赛 Diversity (树形DP)
题目:https://vjudge.net/contest/325352#problem/A 题意:给你一棵树,每个点给一个区间,可以选区间里面任何一个数,然后问怎么安排得到最大边两点之间的差值和,求 ...