SynchronizationContext对Windows Forms窗体控件的更新方法

  众所周知,.NET Framework 支持几种不同类型的应用程序,而每种应用程序所支持的线程模型也不相同。Console、Windows Service应用程序不对线程做任何限制,即在这两种应用程序中,线程可做任何它想做的事;而Windows Forms(从.NET Framework 2.0开始)、WPF、Silverlight支持的线程模型是:窗体控件只允许创建它的线程可以对其进行更新。如果是非创建线程对其更新,在VS中调试时,则会抛出InvalidOperationException异常,并提示:从不是创建控件的线程访问它。虽然在非调试状态下不会抛出这个异常,但这样做不是线程安全的。

  在Windows Forms中,为了解决从非创建线程更新的问题,我们可以通过调用Form.CheckForIllegalCrossThreadCalls属性并将其值设为false,正如前面所说,这不是线程安全的,所以不建议这样做。于是MS为我们提供了一种新的更新方式:通过委托转到创建线程进行更新。比如,我们要在一个非创建线程里对窗体中的一个TextBox控件的Text属性进行更新,我们会写出大致如下的代码: 

ContractedBlock.gifExpandedBlockStart.gif代码
//声明一个委托,DoUpdateUI方法与其签名匹配
delegate void UpdateUIDelegate(TextBox tb, string result);
//更新方法,将更新操作从非创建线程转到创建线程,tb参数代表要更新的控件ID,result代表更新的文本信息
private void DoUpdateUI(TextBox tb, string result)
{
  if (tb.InvokeRequired)
  {
    UpdateUIDelegate d
= new UpdateUIDelegate(DoShowUI);
    this.Invoke(d, new object[] { tb, result });
  }
  else
  {
    tb.Text
= result;
  }
}


 


  如果要在非创建线程中对控件进行更新,我们只需调用DoUpdateUI方法,并传入相应参数即可。也许你可能觉得这样不方便,那好,这篇博客要讲的重点就是一种新的更新方法。

  在System.Threading命令空间下,有个SynchronizationContext类,我们可以通过SynchronizationContext.Current获得与当前应用程序类型对应的SynchronizationContext派生类的引用(Console程序类型会返回null)。SynchronizationContext类的定义大致如下代码所示:

 

ContractedBlock.gifExpandedBlockStart.gif代码
public class SynchronizationContext {
public static SynchronizationContext Current { get; }
public virtual void Post(SendOrPostCallback d, object state); // Call asynchronously
public virtual void Send(SendOrPostCallback d, object state); // Call synchronously
}

 

它有两个方法,Post和Send。在Windows Forms中,SynchronizationContext的派生类的Post方法会调用System.Windows.Forms.Control.BeginInvoke 方法,而Send方法则调用的是 System.Windows.Forms.Control.Invoke 方法,所以推荐使用Post方法,因为它是异步的,代表着更高的性能。

  下面的代码演示了利用SynchronizationContext类的派生类在非创建线程中更新窗体控件,你会觉得比起直接用委托更加简单些了。

ContractedBlock.gifExpandedBlockStart.gif代码
private void btnTest_Click(object sender, EventArgs e)
{
  //此处获取创建线程的SynchronizationContext类引用,并传给线程池线程
SynchronizationContext currentAsync
= SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(Execute, currentAsync);
}

private void Execute(object status)
{
SynchronizationContext currentAsync
= status as SynchronizationContext;
if (currentAsync != null)
{
   //在线程池中通过Post方法更新窗体控件
currentAsync.Post((obj)
=> { lbStatus.Text = obj.ToString(); }, "创建对象成功!");
}
}

  总结:由于Windows Forms、WPF、Silverlight应用程序类型的线程模型原因,同时,也为了线程同步安全性的考虑,我们对窗体控件的更新最好转到创建线程中去。本文演示了SynchronizationContext派生类在非创建线程中对Windows Forms窗体控件的更新,虽然本质上没有变化,但我觉得,在很多时候,比直接用委托方式更加简单。


转载于:https://www.cnblogs.com/myshell/archive/2010/05/23/1742145.html

C# WinForms纯代码开发实战:从入门到构建完整桌面应用 桌面应用程序开发是软件开发中的重要领域,它允许开发者构建直接运行在操作系统上的本地应用。其核心原理在于通过图形用户界面(GUI)框架与用户交互,并利用本地系统资源实现高效性能。在众多GUI框架中,C# Windows Forms(WinForms)因其快速开发、丰富的控件库和与.NET生态的深度集成,成为构建Windows桌面应用的主流选择之一。纯代码开发方式摒弃了传统的可视化设计器,完全通过编写C#代码来动态创建和配置界面控件,这不仅能深化对WinForms事件委托模型和控件树等底层机制的理解,更能实现高 阅读详情

相关推荐

C#上位机开发:基于委托的跨线程UI日志更新实战

在C#桌面应用开发中,跨线程访问UI控件是一个常见挑战,直接操作会引发InvalidOperationException异常。其核心原理在于Windows窗体或WPF的UI线程模型要求控件的创建与修改必须在同一线程内完成,以确保线程安全与界面一致性。为解决此问题,C#的委托机制提供了优雅的方案,它不仅是类型安全的方法指针,更是实现观察者模式、解耦前后端逻辑的关键。通过定义委托事件,后台线程可将更新任务封装为委托,并利用Control.Invoke或BeginInvoke方法安全地“封送”到UI线程执行,从而

cuemes08808的博客 570

同步上下文(SynchronizationContext) 和 C#中跨线程更新UI的方法总结

在C#编程环境中,不允许在工作线程中直接对主线程(UI线程)中的控件进行更新操作。因此,稍微复杂一点的程序,跨线程更新UI界面是非常常见的。目前,一般有以下几种方法可以实现在工作线程对UI控件的更新: 通过UI线程的SynchronizationContext的Post/Send方法更新 通过UI控件的Invoke/BeginInvoke方法更新 通过BackgroundWorker取代Thread执行异步操作 通过取消线程安全检查来避免"跨线程操作异常" 1 通过UI线程的SynchronizationC

kalvin_y_liu的博客 7522

C# 深入掌握 WinForms 多线程打开多个窗体的技术

通过本文的学习,您已经掌握了在 WinForms 应用程序中使用多线程技术打开多个窗体的方法。无论是使用TaskThreadPool还是,都可以有效地实现这一目标。记住,正确的线程管理和线程间通信是构建高效且可靠的 WinForms 应用程序的关键。如果您有任何疑问或建议,欢迎随时留言交流!期待与大家一起探索更多有趣的技术知识。

墨夶的博客 889

C# 异步编程 WinForm中的常见问题

Winform窗体编程中,用到基于任务的多线程处理时,常见的跨线程调用UI和死锁问题的原因与解决方式。

Raink的博客 6578

使用SynchronizationContext进行跨线程调用

子线程访问界面线程的资源会产生跨线程调用的错误,虽然可以通过设置CheckForIllegalCrossThreadCalls来避免此错误但是往往会产生新的问题,使用界面的线程的InvokeRequired或者SynchronizationContext都可以解决此问题,个人更喜欢后者。

从‘全步’到‘微步’:一张图看懂步进电机细分控制,选对模式让你的项目更丝滑

本文深入解析步进电机细分控制技术,从全步到微步的演进过程,帮助工程师根据项目需求选择最优控制模式。通过对比不同细分等级的性能特点和应用场景,提供3D打印、实验室自动化等领域的黄金配置方案,实现更精准、平稳的电机控制效果。

weixin_29290259的博客 471

C# .NET 使用SynchronizationContext访问主线程

测试运行36小时,未发生异常.且软件效果流畅。

资深全栈开发工程师 1085

CamoFox MCP:让AI助手隐身操作浏览器的反检测自动化实战

浏览器自动化是提升工作效率和实现数据采集的关键技术,其核心原理在于通过程序脚本模拟人类在网页上的交互行为。传统方案如Selenium或Playwright虽功能强大,但需要开发者编写复杂脚本并处理反爬机制。随着AI Agent技术的发展,自然语言驱动的自动化成为新趋势,它能将任务规划与逻辑判断交由AI处理,大幅降低使用门槛。Model Context Protocol(MCP)作为连接AI与外部工具的标准协议,在此场景下价值凸显,它使得AI助手能直接调用丰富的浏览器操作工具。CamoFox MCP创新性地将

weixin_42551967的博客 726

C# SynchronizationContext以及Send和Post使用总结

C#中,类是一个非常重要的组件,它为不同的同步模型(如Windows Forms、WPF和ASP.NET)提供一个统一的编程模型。这个类主要用于在多线程环境中管理线程之间的上下文切换,特别是涉及UI操作时,确保UI更新等操作在正确的线程上执行。

weixin_42098295的博客 1190

unity 休闲游戏 动效规范说明

在特效制作中,有时为了完成更丰富、更绚丽的效果,可能会添加一些高级Shader(着色器),例如扭曲、溶解,这些Shader(着色器)往往需要用到显卡的部分功能,会造成较大的性能损耗。如果对纹理细节要求较高,那么建议使用贴图比例为1∶1的正方形(不强制),使用不等边贴图制作特效时会对纹理清晰度造成一定的损失(引擎算法决定)。首先选择模型体,然后在Inspector(检测视图)中查看该物体的属性,找到MeshRenderer(网格渲染)组件中的阴影设置项,如图。制作特效时,尽量不要使用灯光系统。

丛小胖 1610

独创改进 | RT-DETR 引入 Asymptotic Hybrid Encoder | 渐进混合特征解码结构

独创改进🚀! | RT-DETR 引入 Asymptotic Hybrid Encoder | 渐进混合特征解码结构

Coding... 2211

了解同步上下文;在Action中的Task.ConfigureAwait

在处理异步代码时,您必须充分理解的最重要的概念之一是同步上下文。同步上下文是异步编程领域中最容易被忽视的概念之一,因为开发人员通常很难理解它。今天,我们将尽可能地简化事情。我们将看看SynchronizationContext类,看看它如何影响代码行为。我们还将了解TPL库中最重要的方法之一Task.ConfigureAwait()。

寒冰屋的专栏 696

ESP32-C3入门教程 环境篇③——VS Code IDE快速入门

文章目录一、安装Visual Studio Code二、安装扩展三、配置ESP-IDF 插件四、创建工程五、配置工程5.1 选择目标芯片5.2 项目配置六、编译工程七、固件分析七、固件下载八、串口日志九、单步调试 一、安装Visual Studio Code 下载并安装Visual Studio Code 二、安装扩展 左侧扩展 搜索espressif 点击安装 三、配置ESP-IDF 插件 按下F1按键 输入configure esp-idf extension EXPRESS,如果你

8304

c#:深入理解SynchronizationContext

环境: window10 vs2019 .net core 3.1 dnSpy v6.1.4 (.NET Core) ILSpy版本6.1.0.5902 一、为什么需要SynchronizationContext? 问题是这样的:在winform中窗体的控件都是由UI线程创建的,当我们点击按钮后如果有耗时操作的话,我们肯定需要单独启动线程去运算,运算完了之后又要访问窗体控件将结果显示出来,但因为窗体控件是由UI线程创建的,所以,winform仅允许我们在UI线程中取操纵窗体控件。 所以有了下面的常见代码

火焰 9168

3、★☛基于STM32的手机通过wifi控LED灯√♠★

3、基于STM32的手机通过wifi控LED灯 文章目录3、基于STM32的手机通过wifi控LED灯1、Introduce介绍1.1、课题背景及其意义1.2、 国内外的研究状况2、方案的设计2.1、控制方案的确定2.2、控制方式的选择2.2.1、 单片机芯片的选择方案一方案二方案三方案四2.2.2、无线遥控模块的选择方案一方案二方案三3、硬件电路的设计3.1、系统的功能分析及体系结构设计3.1.1、系统功能分析3.1.2、系统总体结构3.2、模块电路的设计3.2.1、 STM32单片机核心电路设计3.2.

行走的皮卡丘 2962

【异常】OpenClaw网关仪表盘 pairing required 报错排查与解决方案

在OpenClaw网关仪表盘页面,完成WebSocket URL、网关令牌等必填项配置后,点击「连接」按钮尝试建立网关连接时,页面下方出现红色报错提示框,核心报错内容为,无法完成网关连接建立,且该报错在令牌配置正确、网络链路通畅的场景下仍会触发。该报错常见于非本地回环地址的访问场景,包括局域网远程访问、公网域名/IP访问、云服务器部署的网关远程管理等场景,本地127.0.0.1回环地址访问通常可正常连接。

奶爸的编程之路,也就一周冷个三天 1078

理解SynchronizationContext,如何在Winform里面跨线程访问UI控件

SynchronizationContext 类是一个基类,可提供不带同步的自由线程上下文。 此类实现的同步模型的目的是使公共语言运行库内部的异步/同步操作能够针对不同的异步模型采取正确的行为。此模型还简化了托管应用程序为在不同的同步环境下正常工作而必须遵循的一些要求。同步模型的提供程序可以扩展此类并为这些方法提供自己的实现。(来自MSDN)简而言之就是允许一个线程和另外一个线程进行通讯,Sy...

weixin_34146986的博客 549

推荐系统[九]项目技术细节讲解z2:搜索Query理解[Term Weight、Query 改写、同义词扩写]和语义召回技术

在 pooling 方法上,我们也尝试过不同层 pooling,或者在多层上增加 attention 聚合 BERT 多层结果,效果和最后一层所有 token 做 average pooling 相当。损失函数方面,在排序阶段使用pairwise比 pointwise 损失函数的效果会更好。

丨汀、的博客 1109

如何在子线程中操作窗体上的控件 线程间操作无效

一般来说,直接在子线程中对窗体上的控件操作是会出现异常,这是由于子线程和运行窗体的线程是不同的空间,因此想要在子线程来操作窗体上的控件,是不可能简单的通过控件对象名来操作,但不是说不能进行操作,微软提供了Invoke的方法,其作用就是让子线程告诉窗体线程来完成相应的控件操作。 现在用一个用线程控制的进程条来说明,大致的步骤如下: 1. 创建Invoke函数,大致如下: /// /// Dele

人生不要太仁慈 453

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

LiteDB.Studio架构深度解析:Windows Forms应用的现代设计模式

LiteDB.Studio是一款专为LiteDB v5设计的**图形化数据库管理工具**,它采用了现代Windows Forms应用程序的先进架构设计。这个**数据库管理工具**不仅提供了直观的**SQL查询界面**,还实现了高效的任务管理和UI交互模式,为开发者提供了强大的**LiteDB数据库可视化**能力。 ## 🏗️ 整体架构设计模式 LiteDB.Studio采用了**分层架构设计

gitblog_00350的博客 442

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C#上位机开发实战:后台线程安全更新UI日志的三种解决方案

在C#桌面应用开发中,跨线程访问UI控件是一个常见的技术挑战,尤其在工业控制、数据采集等上位机场景中,后台线程需要实时更新界面日志。其核心原理在于WinForms和WPF的UI线程模型要求控件操作必须在创建它们的线程上执行,直接跨线程访问会引发InvalidOperationException异常。为解决这一问题,开发者通常借助委托(Delegate)机制,通过Invoke或BeginInvoke方法将更新操作封送到UI线程。从技术价值看,这不仅保证了线程安全,避免了界面卡死,还提升了用户体验和系统稳定性。

weixin_34354173的博客 314

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

线程更新UI方法总结

线程更新UI方法总结

xie__jin__cheng的博客 577

C#多线程下更新UI的几种方法

1. 使用UI线程的SynchronizationContext的Post/Send方法,这种情况一般在窗体构造函数或者FormLoad中获取同步上下文; 范例: public partial class Form1 : Form { SynchronizationContext SyncContext = null; public Form...

weixin_30455067的博客 777

C#跨线程安全更新UI控件:委托与Invoke/BeginInvoke实战解析

在C#桌面应用开发中,多线程编程是提升应用响应性和性能的关键技术,但跨线程操作UI控件常引发InvalidOperationException异常。其核心原理在于WinForms/WPF的UI线程单线程公寓模型,要求控件操作必须在创建它的线程上执行。为解决此问题,C#提供了委托机制,结合控件的Invoke或BeginInvoke方法,实现从后台线程到UI线程的安全通信。这一技术对于工业上位机、数据采集监控等需要实时处理串口、网络数据的场景至关重要,能有效避免界面卡顿和内存泄漏。本文通过构建一个线程安全的日志

weixin_34203832的博客 389

C# Winform 跨线程更新UI控件常用方法汇总

概述C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现“线程间操作无效: 从不是创建控件的线程访问它”的异常。处理跨线程更新Winform UI控件常用的方法有4种:1. 通过UI线程的SynchronizationContext的Post/Send方法更新;2. 通过UI控件的Invoke/BeginInvoke方法更新;3. 通过BackgroundWorker取代T...

wzk456的专栏 282

C# WinForm多线程实战:双色球开奖模拟器开发指南

在桌面应用开发中,多线程技术是解决界面卡顿、提升用户体验的核心手段。其原理在于将耗时任务(如数据计算、网络请求)分配到独立的工作线程执行,从而释放UI线程以保持界面响应。这项技术的价值在于能够构建流畅、高效的应用程序,广泛应用于数据处理、实时通信、文件操作等场景。本文以双色球开奖模拟器为例,深入探讨了在WinForm环境中如何安全地实现多线程UI更新,并融入了async/await和CancellationToken等现代C#异步编程模式,为开发者提供了一套完整的工程实践方案。

weixin_33875564的博客 414
上一篇: SQL Server 2008 Express 升级R2全过程
下一篇: ASP.NET MVC 2 模板化辅助方法
devo4561
博客等级 码龄12年 0粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值