WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用

简介:


Control 不能在创建它的 Thread 之外被调用。但可以通过 invoke 来保证 Control 线程安全。

在跨线程更新的时候,Control 会检查 CurrentThread 是否为创建 Control 的线程,并报错!

示例代码如下:

复制代码
示例代码
private void btnStart_Click( object sender, EventArgs e)
{
// 注意:特地不使用 Timer 控件
Thread thread = new Thread(Fun);
thread.Start(DateTime.Now.ToString());
}

// 报错:线程间操作无效: 从不是创建控件“lblTime”的线程访问它。
private void Fun( object datetime)
{
lblTime.Text = ( string)datetime;
}
复制代码


最简单的解决方式是在程序代码中添加如下属性:

Control.CheckForIllegalCrossThreadCalls = false;


在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的做法,Invoke 和 BeginInvoke 就是为了解决这个问题而出现的,使你在多线程中安全的更新界面显示。

将要做的事情放在工作线程中执行,而将对纯粹的界面更新放到 UI 线程中去做,这样也就达到了减轻 UI 线程负担的目的。

使用 BeginInvoke 方法解决该问题的代码如下:

复制代码
使用BeginInvoke方法
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Invoke_Test
{
public partial class Form1 : Form
{

// private System.Windows.Forms.Label lblTime;
// private System.Windows.Forms.Button btnStart;

public Form1()
{
InitializeComponent();
// 解决方式一
// Control.CheckForIllegalCrossThreadCalls = false;
}

private void btnStart_Click( object sender, EventArgs e)
{
string arg = DateTime.Now.ToString();

// 注意:创建子线程间接调用
Thread thread = new Thread(FunStart);
thread.Start(arg); // arg 给方法传参
}

// 定义调用方法的委托
delegate string FunDelegate( string str);

// 注意:特地使用 FunStart 方法模拟间接调用
private void FunStart( object obj)
{
// 要调用的方法的委托
FunDelegate funDelegate = new FunDelegate(Fun);

/* ========================================================
* 使用this.BeginInvoke方法
* (也可以使用this.Invoke()方法)
========================================================
*/

// this.BeginInvoke(被调用的方法的委托,要传递的参数[Object数组])
IAsyncResult aResult = this.BeginInvoke(funDelegate,obj.ToString());

// 用于等待异步操作完成(-1表示无限期等待)
aResult.AsyncWaitHandle.WaitOne(- 1);

// 使用this.EndInvoke方法获得返回值
string str = ( string) this.EndInvoke(aResult);
MessageBox.Show(str.ToString());
}

// 真正需要执行的方法
private string Fun( string datetime)
{
lblTime.Text = ( string)datetime;
return " 委托的返回值 ";
}
}
}
复制代码


Control.InvokeRequired 属性:当前线程不是创建控件的线程时为 true。
也可以认为,在 new Control() 的时候,Control 用一个变量记录下了当前线程,在调用 InvokeRequired 时,返回当前线程是否不等于 new 的时候记录下来的那个线程。

Control.Invoke 和 Control.BeginInvoke 就是“发短信”的方法,如果使用 Control.Invoke 发短信,那么甲线程就会像个痴情的汉子,一直等待着乙线程的回音,而如果使用 Control.BeginInvoke 发送短信,那发完短信后,甲线程就会忙活自己的,等乙线程处理完再来瞧瞧。




本文转自钢钢博客园博客,原文链接:http://www.cnblogs.com/xugang/archive/2010/06/05/1752235.html,如需转载请自行联系原作者

相关文章
|
Java
【Java异常】Feign常见的坑总结之一:Method Not Allowed“,“message“:“Request method ‘POST‘ not supported“,“path“:“/*
【Java异常】Feign常见的坑总结之一:Method Not Allowed“,“message“:“Request method ‘POST‘ not supported“,“path“:“/*
254 0
单方法对象(Single-method Object)
单方法对象(Single-method Object)
104 2
|
数据安全/隐私保护
一步一步学Edit Control控件的用法
Edit Control控件最常见的用法,一般有有以下几种: 1、  显示默认的字符串; 2、  接受用户输入的字符串。 3、  作为密码框接受用户输入的字符串。
1126 0
|
XML 网络安全 Android开发
Volley学习笔记 | 关于源码中Request、Response、Listener泛型的理解(附XMLRequest自定义代码)
Volley学习笔记 | 关于源码中Request、Response、Listener泛型的理解(附XMLRequest自定义代码)
|
Kotlin
【错误记录】布局组件加载错误 ( Attempt to invoke virtual method ‘xxx$Callback android.view.Window.getCallback()‘ )
【错误记录】布局组件加载错误 ( Attempt to invoke virtual method ‘xxx$Callback android.view.Window.getCallback()‘ )
315 0
|
Web App开发 JavaScript 前端开发
给自定义控件(Web Control)添加事件的几种方法。前两种方法可以不实现IPostBackEventHandler
    写自定义控件已经好久了,也有几个用得时间比较长的,但是对于“事件”一直是比较模糊,没有很详细的理解。          最近升级分页控件,由于原来使用的是VB.net(在VB.net里面添加一个事件是比较容易的),现在想改用C#,而原来的方法又写得比较笨拙,想换一个更简洁一点的方法,所以不得不重新认识一下事件。
975 0
|
前端开发
如何使用Action.Invoke()触发一个Storyboard
原文:如何使用Action.Invoke()触发一个Storyboard     一般在我们的项目中,最好是将Storyboard放在前台,然后设置Storyboard的x:key值,通过我们的TryFindResource来查找到当前的Storyboard来启动Stroyboard,这样程序显得比较合理,另外在我们的下面这个例子中,我们通过命令绑定的方式来将2个Storyboard绑定到两个Button上面,当我们点击这两个Storyboard的时候,我们会启动相应的动画,首先来看一下前台设计的xaml代码。
908 0
Edit Control控件操作问题
1、创建对话框并修改对话框属性 2、创建对话框类 3、为对话框添加控件(Edit Control) 4、添加控件变量(控件属性操作修改控件ID) void Cdemo1Dlg::DoDataExchan...
1043 0