当前位置: 首页 > news >正文

VB.NET,C#在线程中修改UI的安全操作

    Private Delegate Sub UpdateTextDelegate(text As String)Private Sub ThreadShowNewMessage(text As String)' 检查当前线程是否是UI线程If Me.InvokeRequired Then' 如果不是UI线程,创建委托实例并InvokeDim d As New UpdateTextDelegate(AddressOf ThreadShowNewMessage)Me.Invoke(d, New Object() {text})Else' 如果是UI线程,直接更新控件'Me.ListBox2.Items.Add(text)Me.ListBox2.Items.Insert(0, text)End IfEnd Sub

在 C# 中实现多线程更新 UI 的方法与VB.NET类似,但语法有所不同。以下是几种常见的实现方式:

方法 1:使用 Control.Invoke/BeginInvoke(经典方式)

private delegate void UpdateTextDelegate(string text);private void ThreadShowNewMessage(string text)
{// 检查当前线程是否是UI线程if (this.InvokeRequired){// 如果不是UI线程,创建委托实例并InvokeUpdateTextDelegate d = new UpdateTextDelegate(ThreadShowNewMessage);this.Invoke(d, new object[] { text });}else{// 如果是UI线程,直接更新控件// this.listBox2.Items.Add(text);this.listBox2.Items.Insert(0, text);}
}

方法 2:使用 Lambda 表达式简化 Invoke

private void ThreadShowNewMessage(string text)
{if (this.listBox2.InvokeRequired){this.listBox2.Invoke(new Action(() => {listBox2.Items.Insert(0, text);}));}else{listBox2.Items.Insert(0, text);}
}

方法 3:使用 TaskScheduler.FromCurrentSynchronizationContext(推荐)

private TaskScheduler _uiScheduler;protected override void OnLoad(EventArgs e)
{base.OnLoad(e);_uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); // 保存UI线程的调度器
}private void ThreadShowNewMessage(string text)
{// 使用Task在UI线程上执行Task.Factory.StartNew(() => {listBox2.Items.Insert(0, text);}, CancellationToken.None, TaskCreationOptions.None, _uiScheduler);
}

方法 4:使用 async/await(最简洁)

csharp

private async void ThreadShowNewMessage(string text)
{if (!this.listBox2.InvokeRequired){listBox2.Items.Insert(0, text);return;}// 等待在UI线程上执行await Task.Run(() => {this.listBox2.Invoke(new Action(() => {listBox2.Items.Insert(0, text);}));});
}

方法 5:使用 Dispatcher(WPF 应用)

如果是 WPF 应用,需要使用 Dispatcher 替代 Control.Invoke

private void ThreadShowNewMessage(string text)
{if (this.Dispatcher.CheckAccess()) // 检查是否在UI线程{listBox2.Items.Insert(0, text);}else{this.Dispatcher.Invoke(() => {listBox2.Items.Insert(0, text);});}
}

调用示例 在工作线程中调用上述方法:

// 示例1:在新线程中调用
new Thread(() => {ThreadShowNewMessage("来自工作线程的消息");
}).Start();// 示例2:使用Task
Task.Run(() => {ThreadShowNewMessage("来自Task的消息");
});

关键区别总结

特性Control.InvokeTaskSchedulerasync/await
语法复杂度中等较低最低
线程安全性
异常处理需要在 Invoke 内部捕获可通过 Task 处理异常可使用 try/catch 直接处理
适用场景所有.NET Framework 应用需要精确控制线程调度的场景异步编程场景

最佳实践

  1. 优先使用 async/await:语法最简洁,适合现代 C# 开发。
  2. 避免频繁 Invoke:如果需要更新大量数据,考虑批量处理后再更新 UI,减少 UI 线程负担。
  3. 使用弱引用:在长时间运行的后台任务中,避免直接引用 UI 控件,防止内存泄漏。
  4. 异常处理:确保在 UI 更新代码中包含适当的异常处理,避免因异常导致 UI 线程崩溃。

根据您的具体场景选择合适的方法,async/await 是当前推荐的方式,因为它提供了更清晰的异步代码结构。

http://www.lqws.cn/news/478531.html

相关文章:

  • rknn优化教程(三)
  • WEB3开启 Hardhat 自动验证有什么意义
  • uview ui request get / post 传参含params和json数据的分析和使用
  • 【Redis】解码Redis中hash类型:理解基础命令,以及内部编码方式和使用场景
  • 原创模板--微信小程序 实现的背单词程序
  • 62-Oracle ADR(Automatic Diagnostic Repository)
  • 二、Generative adversarial network (GAN)
  • Spring Boot Actuator 跟踪HTTP请求和响应
  • 【数据结构与算法】数据结构初阶:详解顺序表和链表(一)
  • C++,Qt事件处理机制编程开发练习全解析,23000字解析!!
  • RabbitMQ从入门到实践:消息队列核心原理与典型应用场景
  • Oracle 数据库查询:单表查询
  • 嵌入式通信协议框架的四层架构设计与实现
  • 【云原生】Docker 部署 Elasticsearch 9 操作详解
  • 华为OD-2024年E卷-字符串化繁为简[200分] -- python
  • 「Linux文件及目录管理」vi、vim编辑器
  • Ragflow 源码:task_executor.py
  • Sqlserver 设置对特定数据库特定表只读访问权限
  • 1928: 日期差值 codeup
  • MySQL安装与配置【windowsMac】
  • Unity3D仿星露谷物语开发69之动作声音
  • Unity Addressable使用之服务器远程加载
  • leetcode:面试题 08.01. 三步问题
  • AWS认证系列:考点解析 - cloud trail,cloud watch,aws config
  • JavaEE-Mybatis初阶
  • ubuntu24.04+5090显卡驱动安装踩坑
  • C4.5算法深度解析:决策树进化的里程碑
  • 低空经济三大赛道深度解析:交通、安防、能源领域的革命性突破
  • 华为公布《鸿蒙编程语言白皮书》V1.0 版:解读适用场景
  • es中向量索引的增量更新