惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 司徒正美
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
MongoDB | Blog
MongoDB | Blog
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
D
Docker
S
Secure Thoughts
B
Blog
M
MIT News - Artificial intelligence
P
Privacy International News Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
A
Arctic Wolf
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
SegmentFault 最新的问题
WordPress大学
WordPress大学
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Tenable Blog
Last Week in AI
Last Week in AI
A
About on SuperTechFans
T
Tor Project blog
Microsoft Azure Blog
Microsoft Azure Blog
Hugging Face - Blog
Hugging Face - Blog
月光博客
月光博客
L
Lohrmann on Cybersecurity
Security Latest
Security Latest
P
Proofpoint News Feed
有赞技术团队
有赞技术团队
P
Privacy & Cybersecurity Law Blog
Spread Privacy
Spread Privacy
AWS News Blog
AWS News Blog
P
Proofpoint News Feed
云风的 BLOG
云风的 BLOG
小众软件
小众软件
宝玉的分享
宝玉的分享
量子位
Forbes - Security
Forbes - Security
T
Threatpost
Google DeepMind News
Google DeepMind News
T
Threat Research - Cisco Blogs
H
Help Net Security
Help Net Security
Help Net Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
T
Troy Hunt's Blog
SecWiki News
SecWiki News
I
InfoQ
C
Cyber Attacks, Cyber Crime and Cyber Security
Stack Overflow Blog
Stack Overflow Blog

博客园 - lzhdim

近十年最帅风冷!酷冷至尊V8 ACE 3DHP散热器评测:单塔能干翻双塔 20260723 - 个人小作品更新 C# 中读取CPU、硬盘和内存温度 雷柏VT3s MAX鼠标评测:中小手型用户也没有被遗忘 顶尖性能的小号电竞鼠标来了 JavaScript 中的原型与继承 1分钟查清局域网所有IP 20260714 - 个人小作品更新 WorkBuddy 完整教程手册 专为AI而生的企业级QLC SSD!长江存储PE501 61.44TB评测:超过1PB的写入测试 32GB显存才是第一生产力!英特尔锐炫 Pro B70评测:中小企业AI降本神器 JavaScript中的this关键字 C#开发的PopoSaver泡泡屏保应用 - 开源研究系列文章 - 个人小作品 6天不间断测试告诉你到底有多省电!米家空调巨省电大1.5匹评测:制冷峰值功率不超过500W 三倍双摄加持 + D-Log 2 曲线!大疆DJI OSMO Pocket 4P全面评测:补齐短板,化身口袋电影机 晶栈4.0闪存立威!长江存储致态TiPro9000 2TB SSD评测:缓外写入超4GB/s独一档 C# 多线程同步机制详解:原理、使用与性能对比 JavaScript作用域与闭包讲解 最受欢迎的 10 大免费 AI 工具 六种AI生意,从月入一万到月入十万 5个国产大模型实测对比2026:DeepSeek、Kimi、豆包、通义、智谱哪个好用 豆包、元宝、千问、Kimi、DeepSeek,这么多AI软件,到底该用哪个? 微软免费开源了一个 Linux 操作系统,没错!是微软出品 一次看懂5种咖啡冲煮方式:意式、手冲、法压、冷萃、摩卡壶到底有什么区别 120个 实用CSS 技巧汇总合集 JavaScript运算符与表达式详解 C#开发的ScreenSaver屏保应用 - 开源研究系列文章 - 个人小作品 JavaScript变量与数据类型详解 苹果良心!iOS 27适配设备公布:30款机型 7年前的iPhone 11还能升级 C++图形用户界面开发入门 10个不该免费的GitHub神级项目 JavaScript语言全面概述:从历史到现代实践 一张图看懂常见咖啡 C盘空间多出来4GB:谷歌服软 Chrome本地AI大模型可禁用、删除了 96GB显存运行230B大模型!七彩虹灵创K16笔记本评测:160W性能释放 AMD锐龙AI Max+ 395加持全能移动AI工作站 AI PC最强存储搭档!雷克沙NM1090 PRO 8TB固态评测:14400MB/s满速不缩水 C#已经不是当年的C#了——我用它写了个微秒级数据库引擎 EasyTool:轻量全能的 .NET 工具类库 SQL 入门 17:MySQL 数据类型:从字符串到 JSON 的全面解析 SQL 入门 16:SQL 事务隔离级别与死锁解析(易懂) 原相3955XM+TL3228主控!小米电竞鼠标2全面评测:原生双8K究竟有多强 PCIe 4.0火力全开:闪迪奥丁马仕GX 7100 NVMe SSD上手 超乎预料的千元级电竞主板!七彩虹iGame B850M Ultra-OC V14主板评测 SQL 入门 15:SQL 事务:从 ACID 到四种常见的并发问题 名人 - 我的闪存 C#性能优化技巧 SQL 入门 14:SQL 触发器与事件:自动化数据处理 38个实用的JavaScript 技巧 一款基于 .Net WinForm 开发的节点编辑器,纯 GDI 实现,体积仅 100+Kb Masuit.Tools:这个 C# 工具库 SQL 入门 13:SQL 存储过程与函数:封装逻辑与参数处理 49个 JavaScript 代码快捷技巧,让你在 2026 年成为代码高手 20260503 - 个人小作品更新 SQL 入门 12:SQL 视图:创建、修改与可更新视图 C#如何实现Windows系统桌面截图功能... 6999元AMD新旗舰首测!锐龙9 9950X3D2性能解禁:这颗U根本不是给游戏玩家造的 SQL 入门 11:日期时间格式化、IF、CASE的使用 基于C#的校时类库的实现及使用 - 开源项目研究文章
WinForm 中跨线程操作 UI 的解决方案
lzhdim · 2026-06-18 · via 博客园 - lzhdim

前言

在开发WinForm应用程序时,经常会遇到需要在线程间操作UI的情况。直接从非UI线程更新UI控件会导致异常,因此我们需要采取适当的方法来安全地进行这些操作。本文总结了几种常见的解决方法,并对其优缺点进行了分析。

正文

方法一:禁用线程间的非法调用检查

这是最简单的方法,但也是最不推荐的做法。通过设置窗体属性Control.CheckForIllegalCrossThreadCalls = false;可以取消线程间的安全检查,从而允许跨线程更新UI。

然而,这种方法可能导致不稳定和不安全的行为,应避免使用。

public partialclassone : Form
{
    public one()
    {
        InitializeComponent();
        Control.CheckForIllegalCrossThreadCalls = false;
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Thread listen = new Thread(new ThreadStart(receive));
        listen.IsBackground = true;
        listen.Start();
    }
    private void receive()
    {
        UdpClient uc = new UdpClient(5839);
        while (true)
        {
            IPEndPoint ip = null;
            byte[] message = uc.Receive(ref ip);
            string messagestring = Encoding.UTF8.GetString(message);
            textBox1.Text = messagestring;
        }
    }
}

方法二:使用全局变量结合Timer实现

该方法利用了全局变量存储数据,并通过定时器(Timer)周期性地更新UI。虽然这种方法实现了目标,但由于它依赖于Timer的频率,可能会导致不必要的延迟和资源消耗。

public partialclasstwo : Form
{
    string messagestring = "";

    public two()
    {
        InitializeComponent();
    }

    private void two_Load(object sender, EventArgs e)
    {
        Thread listen = new Thread(new ThreadStart(receive));
        listen.IsBackground = true;
        listen.Start();
        timer1.Start();
    }

    private void receive()
    {
        UdpClient uc = new UdpClient(5839);
        while(true)
        {
            IPEndPoint ip = null;
            byte[] message = uc.Receive(ref ip);
            messagestring = Encoding.UTF8.GetString(message);
        }
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        textBox1.Text = messagestring;
    }
}

方法三:使用BackgroundWorker组件

使用BackgroundWorker可以简化异步编程模型,适合处理简单的后台任务。

但是,它的局限性在于仅适用于Windows Forms,对于其他平台则不适用。

public partialclassthree : Form
{
    public three()
    {
        InitializeComponent();
    }

    private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
    {
        UdpClient uc = new UdpClient(5839);
        while(true)
        {
            IPEndPoint ip = null;
            byte[] message = uc.Receive(ref ip);
            string messagestring = Encoding.UTF8.GetString(message);
            backgroundWorker2.ReportProgress(50, messagestring);
        }
    }

    private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        textBox1.Text = e.UserState.ToString();
    }
}

方法四:使用SynchronizationContext

通过SynchronizationContext的Post或Send方法可以在不同线程之间传递消息,确保UI更新安全执行。

这是一种较为灵活且可靠的方式。

public partialclassfourth : Form
{
    SynchronizationContext SyncContext = null;

    public fourth()
    {
        InitializeComponent();
        SyncContext = SynchronizationContext.Current;
    }

    private void receive()
    {
        UdpClient uc = new UdpClient(5839);
        while (true)
        {
            IPEndPoint ip = null;
            byte[] message = uc.Receive(ref ip);
            string messagestring = Encoding.UTF8.GetString(message);
            SyncContext.Post(change,messagestring);
        }
    }

    private void change(object str)
    {
        textBox1.Text = str.ToString();
    }
}

方法五:使用Invoke或BeginInvoke

这是目前最常用的跨线程更新UI的方法。通过控件的Invoke或BeginInvoke方法将委托调度到UI线程上执行,保证了线程安全性。

public partialclassfifth : Form
{
    delegate void Change(string text);

    public fifth()
    {
        InitializeComponent();
    }

    private void Settext(string text)
    {
        textBox1.Text = text;
    }

    private void receive()
    {
        UdpClient uc = new UdpClient(5839);
        while (true)
        {
            IPEndPoint ip = null;
            byte[] message = uc.Receive(ref ip);
            string messagestring = Encoding.UTF8.GetString(message);
            this.BeginInvoke(new Change(Settext),messagestring);
        }
    }
}

总结

跨线程操作UI是WinForm开发中常见的挑战之一。尽管有多种方式可以解决这个问题,但考虑到安全性和灵活性,推荐使用SynchronizationContext或者控件的Invoke/BeginInvoke方法。正确理解并应用委托机制对有效管理多线程环境下的UI更新至关重要。