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属性,系统会抛出一个 ...
随机推荐
- Phonegap-----Media
Everything in the code: <!DOCTYPE html> <html> <head> <title>Media Example&l ...
- hdu 5057 Argestes and Sequence
Argestes and Sequence Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
- ListView下拉刷新及上拉更多两种状态
一.前言: 很多应用都会用到ListView,当然如果是iOS就会用UITableViewController,这两个控件在不同的OS上,功能是一样的,只是有些细微的不同(iOS的UITableVie ...
- 【JQuery】eval()出现missing after property id 错误。
是因为数据没有转换成json格式输出就直接eval了. 正确步骤:后台: JsonBinder.buildNormalBinder().toJson(list); 前台: eval('(${posit ...
- Android中EditText,Button等控件的设置
EditText可以使用:TextView.setEnabled(true)来设置为可编辑,其实很简单,写在这里以便以后自己查看. Button设置可用性:setVisibility(View.VIS ...
- Android广播——短信拦截
MainActivity.java package com.example.broadcasttest; import android.content.Intent; import android.c ...
- Codeforces 482 - Diverse Permutation 构造题
这是一道蛮基础的构造题. - k +(k - 1) -(k - 2) 1 + k , 1 , k , 2, ....... ...
- RunLoop学习总结
开始 很久之前就看了一次YY的文章,没看懂.后来又看了sunny的视频和叶孤城的直播的视频,找了很多资料,对RunLoop也越来越清晰,然后又看了两三次YY的文章,虽然还没完全看懂,不得不说写的非常好 ...
- 基于visual Studio2013解决C语言竞赛题之0514单词统计
题目 解决代码及点评 /************************************************************************/ /* 14. 有一行字 ...
- java里,当long与上了int
long switchState = 0xf0000000000L; int result = (switchState & 0xff00000000L) > 0 ? 0x01 : 0x ...