WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用
Control 不能在创建它的 Thread 之外被调用。但可以通过 invoke 来保证 Control 线程安全。
在跨线程更新的时候,Control 会检查 CurrentThread 是否为创建 Control 的线程,并报错!
示例代码如下:

{
//注意:特地不使用 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 方法解决该问题的代码如下:

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 发送短信,那发完短信后,甲线程就会忙活自己的,等乙线程处理完再来瞧瞧。
推荐阅读:WinForm二三事(三)Control.Invoke&Control.BeginInvoke
示例代码:Invoke_Test
作者: XuGang 网名:钢钢 |
出处: http://xugang.cnblogs.com |
声明: 本文版权归作者和博客园共有。转载时必须保留此段声明,且在文章页面明显位置给出原文连接地址! |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构