Control.Invoke和Control.BeginInvoke
问题的引入
下面有个简单的demo,大家一看代码就知道效果如何示例。我新建一个winform的程序,然后写入了如下代码:
using System;
using System.Windows.Forms; namespace MyExampleList
{
public partial class ControlInvokeExample : Form
{
public ControlInvokeExample()
{
InitializeComponent();
} private void btnSayHello_Click(object sender, EventArgs e)
{
txtHello.Text = "祝你学习C#愉快";
}
}
}
运行效果如下:
[caption id="attachment_1150" align="alignnone" width="364"] 显示文本[/caption]
下面我来改造一下这个简单的demo。我们在编程的时候使用多线程是非常的常见,我们在点击按钮的时候启用另一个线程,然后来操作textbox的值,让它进行变化,代码如下:
using System;
using System.Threading;
using System.Windows.Forms; namespace MyExampleList
{
public partial class ControlInvokeExample : Form
{
public ControlInvokeExample()
{
InitializeComponent();
} private void btnSayHello_Click(object sender, EventArgs e)
{
Thread th=new Thread(new ThreadStart(StartMethord));
th.Start(); } private void StartMethord()
{
txtHello.Text = "祝你学习C#愉快";
}
}
}
理论上就应该是上面的代码就可以执行的,但是实际上会报错,具体错误如下图所示:
[caption id="attachment_1152" align="alignnone" width="860"] 线程交互错误[/caption]
错误解释:上面的错误意思就是txtHello这个控件不是th创建的所以th线程不能直接访问它,因此报错了。
那我们如何让th线程也能改变UI中的txtHello这个textbox的值呢?
我们通过Control.Invoke或者Control.BeginInvoke来实现。
Control.Invoke和Control.BeginInvoke
Control.Invoke:在拥有此控件的基础窗口句柄的线程上执行指定的委托。
Control.BeginInvoke:在创建控件的基础句柄所在线程上异步执行指定委托。
根据上面的解释我们来修改一下上面出错的代码,用Invoke的方式来实现th线程更改txtHello的内容,具体代码如下(我称下面的这种实现方式为:A):
using System;
using System.Threading;
using System.Windows.Forms; namespace MyExampleList
{
public partial class ControlInvokeExample : Form
{
public ControlInvokeExample()
{
InitializeComponent();
}
delegate void InvokeDelegate();
private void btnSayHello_Click(object sender, EventArgs e)
{
Thread th=new Thread(new ThreadStart(StartMethord));
th.Start();
}
private void StartMethord()
{
txtHello.Invoke(new InvokeDelegate(ChangeTextBox));
}
private void ChangeTextBox()
{
txtHello.Text = "祝你学习C#愉快";
}
}
}
用BeginInvoke的方式来实现th线程更改txtHello的内容,具体代码如下(我称下面的这种实现方式为:B):
using System;
using System.Threading;
using System.Windows.Forms; namespace MyExampleList
{
public partial class ControlInvokeExample : Form
{
public ControlInvokeExample()
{
InitializeComponent();
}
delegate void InvokeDelegate();
private void btnSayHello_Click(object sender, EventArgs e)
{
Thread th=new Thread(new ThreadStart(StartMethord));
th.Start();
}
private void StartMethord()
{
txtHello.BeginInvoke(new InvokeDelegate(ChangeTextBox));
}
private void ChangeTextBox()
{
txtHello.Text = "祝你学习C#愉快";
}
}
}
我们对比一下A和B两种实现方式,在代码上的区别,唯一的区别就是A使用了txtHello.Invoke和B方式用了txtHello.BeginInvoke,也就是他们的区别又归到了Invoke和BeginInvoke上,一个是同步,一个是异步,也就是A方式的时候是等待Invoke的执行结果,而B方式的时候是直接执行下去不等待BeginInvoke的执行结果。在本例的demo中方式A和B实现的效果相同,但是原理不同,仅此而已。下面我来重新写一个新的demo,让大家见识一下这两个方法的区别。
修改后的实例代码如下:
using System;
using System.Threading;
using System.Windows.Forms; namespace MyExampleList
{
public partial class ControlInvokeExample : Form
{
public ControlInvokeExample()
{
InitializeComponent();
}
delegate void InvokeDelegate();
private void btnSayHello_Click(object sender, EventArgs e)
{
Thread th=new Thread(new ThreadStart(StartMethord));
th.Start(); }
private void StartMethord()
{
DateTime dt1 = DateTime.Now;
txtHello.Invoke(new InvokeDelegate(ChangeTextBox));//等待ChangeTextBox方法执行完毕,所以str的值比较大
// txtHello.BeginInvoke(new InvokeDelegate(ChangeTextBox));//不等待ChangeTextBox方法执行完毕,所以str的值会很小
string str= (DateTime.Now - dt1).TotalMilliseconds.ToString(); }
private void ChangeTextBox()
{
Thread.Sleep(3000);
txtHello.Text = "祝你学习C#愉快"+DateTime.Now.ToString();
}
}
}
运行后的结果如下两图:
[caption id="attachment_1154" align="alignnone" width="630"] invoke结果[/caption]
[caption id="attachment_1155" align="alignnone" width="584"] BeginInvoke结果[/caption]
差距很明显了吧。
那么什么时候我们必须使用Invoke和BeginInvoke呢?
InvokeRequired:获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程(本例中的UI线程)以外的线程(自定义线程th)中。
也就是当InvokeRequired为true时我们必须用Invoke或者BeginInvoke方法来更新界面。
特别注意
Control的Invoke和BeginInvoke的委托方法是在主线程,即UI线程上执行的。也就是说如果你的委托方法用来取花费时间长的数据,然后更新界面什么的,千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死。
那么,这个异步到底是什么意思呢?(具体的解释可以看上面的A和B方式,指的是th线程的异步)
异步是指相对于调用BeginInvoke的线程异步,而不是相对于UI线程异步,你在UI线程上调用BeginInvoke ,当然不行了。----摘自"Invoke和BeginInvoke的真正涵义"一文中的评论。
BeginInvoke的原理是将调用的方法Marshal成消息,然后调用Win32 API中的RegisterWindowMessage()向UI窗口发送消息。----摘自"Invoke和BeginInvoke的真正涵义"一文中的评论。
Control.Invoke和Control.BeginInvoke的更多相关文章
- 千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死
原文地址:https://www.cnblogs.com/wangchuang/archive/2013/02/20/2918858.html .c# Invoke和BeginInvoke 区别 Co ...
- C#Delegate.Invoke、Delegate.BeginInvoke And Control.Invoke、Control.BeginInvoke
作者:EasonLeung 一.Delegate的Invoke.BeginInvoke 1.Delegate.Invoke (委托同步调用) a.委托的Invoke方法,在当前线程中执行委托. b.委 ...
- C#中的线程二(Cotrol.BeginInvoke和Control.Invoke)
C#中的线程二(Cotrol.BeginInvoke和Control.Invoke) 原文地址:http://www.cnblogs.com/whssunboy/archive/2007/06/07/ ...
- (转)c# control.Invoke control.BeginInvoke
在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate. 一.为什么Control类提供了Invoke和BeginInvoke机制? 关于这个问题的最主要的原因已经是do ...
- WinForm二三事(三)Control.Invoke&Control.BeginInvoke
http://www.cnblogs.com/yuyijq/archive/2010/01/11/1643802.html 这个系列从2009年写到2010年,差点又成太监文.随着WPF/Silver ...
- (转)C#为什么要使用Invoke,它和BeginInvoke有什么区别
在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate. 一.为什么Control类提供了Invoke和BeginInvoke机制? 关于这个问题的最主要的原因已经是do ...
- [C#] Control.Invoke方法和跨线程访问控件(转载)
转载前,在网上找了好多INVOKE方法的文章,就这个看着还可以,明白了大概,以后再深用的时候再研究 ,废话少说上转载(连转载都说的这么有气势,哈哈) 在设计界面时,我们经常需要将一些需要时间才能完 ...
- [C#] Control.Invoke方法和跨线程访问控件
在设计界面时,我们经常需要将一些需要时间才能完成的操作放在另一个线程(不同于UI主线程)中执行.但是这些操作可能需要将其结果或完成情况通知主线程,比如调用窗体的方法,或者触发事件(由界面响应事件),很 ...
- 在.Net中进行跨线程的控件操作(上篇:Control.Invoke)
本文的重点在于介绍如何在多线程编程中,从非UI线程上访问界面中的控件.有过多线程编程经验的人都知道,当我们在非UI线程上试图给一个界面中的控件赋值的时候,比如说label的Text属性,系统会抛出一个 ...
随机推荐
- Javabyte[]数组和十六进制String之间的转换Util------包含案例和代码
Java中byte用二进制表示占用8位,而我们知道16进制的每个字符需要用4位二进制位来表示(23 + 22 + 21 + 20 = 15),所以我们就可以把每个byte转换成两个相应的16进制字符, ...
- 如何使用W5300实现ADSL连接(一)
在介绍W5300连接ADSL之前,先给大家简单介绍一下WIZnet W5300这款芯片. W5300是WIZnet公司的一款单芯片器件,采用0.18μmCMOS工艺,内部集成10/100M以太网控制器 ...
- hadoop、spark/storm等大数据相关视频资料汇总下载
小弟不才,工作中也用到了大数据的相关东西.一開始接触的时候,是通过买来的教学视频入的门.这两天整理了一下自己的视频资料.供各位进行下载. 文档截图:
- leetcode_question_62 Unique Paths
A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...
- (step5.1.3)hdu 1213( How Many Tables——1213)
题目大意:输入两个整数n,m.分别表示点数.对点的操作的次数.在接下来的m行中,每行有两个整数a,b.表示a和b是好朋友.(不是好朋友的不能坐在同一个桌子上) .求需要多少张桌子 解题思路:并查集 1 ...
- 循环调用修正sic86
create or replace procedure rebuild_sic86_wyl(pi_aac001 in number, po_fhz out varchar2, po_msg out v ...
- CentOS的MySQL报错:Can't connect to MySQL server
原文链接: http://www.centoscn.com/CentosBug/softbug/2015/0622/5709.html 问题描述: 使用客户端远程登录连接基于CentOS 6.5服务器 ...
- HDU 3917 最大权闭合图 求最小割
具体参考http://blog.csdn.net/power721/article/details/6665750 TODO //#pragma comment(linker, "/STAC ...
- Android自定义组合控件:UIScrollLayout(支持界面滑动及左右菜单滑动)
一.前言: 我之前很早的时候,写过一篇<左右滑出菜单>的文章: http://blog.csdn.net/qingye_love/article/details/8776650 用的是对V ...
- DH11数字温湿度传感器
DH11数字温湿度传感器是一种集温度.湿度一体的复合传感器,它能把温度和湿度物理量通过温.湿度敏感元件和相应电路转化成方便计算机.PLC.智能仪表等数据采集设备直接读取的数字量.DHT11由电阻式感湿 ...