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 窗体中 ...
随机推荐
- 关于webpack高版本向低版本切换 如何切换?
卸载:npm uninstall webpack -g 重新安装:npm install webpack@3.7.1 -g 直接安装指定版本就行了,如安装 2.4.1 版:cnpm install w ...
- man(2) readv writev
#include <sys/uio.h> ssize_t readv(int fd, const struct iovec *iov, int iovcnt); unix高级环境编程中的定 ...
- SQL 1 数据库 表的操作
数据库:是按照数据结构来组织.存储和管理数据的建立在计算机存储设备上的仓库.一句话就是存储数据的仓库 数据库的分类:网络数据库.层级数据库.关系结构数据库. 倘若按照数据库的存储介质来分:关系型数据库 ...
- java selenium常用API汇总
(WebElement.iFrame.select.alert.浏览器窗口.事件.js) 一 WebElement相关方法 1.点击操作 WebElement button = driver. ...
- Spring中都用到了哪些设计模式
JDK 中用到了那些设计模式?Spring 中用到了那些设计模式?这两个问题,在面试中比较常见.我在网上搜索了一下关于 Spring 中设计模式的讲解几乎都是千篇一律,而且大部分都年代久远.所以,花了 ...
- Change the environment variable for python code running
python程序运行中改变环境变量: Trying to change the way the loader works for a running Python is very tricky; pr ...
- iOS---如何截图,如何将图片保存到相册
最近的项目中运用到了这两个功能,所以记录一下.做了一个小工程将两个方法结合到了一起 1 - (void)viewDidLoad { [super viewDidLoad]; UIButton * bt ...
- 5,Vector
一,Vector简介 1,Vector 是矢量队列,它是JDK1.0版本添加的类. 2,Vector 继承了AbstractList,实现了List:所以,它是一个队列,支持相关的添加.删除.修改.遍 ...
- dede标签大全
想必很多人对后台不熟悉,并且觉得很难.其实不难,只是你们没有找到合适的方法学习而已!只有找到一个合适的学习方法,不管做什么事情,我想都很容易.学习讲究的是效率,而效率又是由思路决定的.就拿网页制作来说 ...
- bzoj 做起走 -- bzoj 1009 GT 考试
现在每次做一道bzoj上的题,整个人都感觉升华了... 先是在网上各种搜题解.要么只有代码,要么有点讲解看不懂,对于从来没有耐心看完别人代码的我,只能一篇一篇的翻..然后终于在某2011级同学的某段话 ...