当前位置: 首页 > 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 是当前推荐的方式,因为它提供了更清晰的异步代码结构。

相关文章:

  • Oracle 数据库查询:单表查询
  • Portable Watch:基于STM32的便携智能手表
  • (三十四)深度解析领域特定语言(DSL)第六章——语法分析:第三个案例——优惠规则语法分析器
  • (线性代数最小二乘问题)Normal Equation(正规方程)
  • 跨个体预训练与轻量化Transformer在手势识别中的应用:Bioformer
  • springboot通过独立事务管理器实现资源隔离与精准控制​
  • 2025最新Python 100个常用函数在线体验项目
  • CSP-S 模拟赛一总结(T1、T2)
  • 秋招Day14 - MySQL - SQL优化
  • Java面试复习指南:JVM原理、并发编程与Spring框架
  • JAVA锁机制:对象锁与类锁
  • Windows/Linux系统 Ollama部署deepseek 大模型
  • 区块链:什么是DeFi?
  • C++ 中 QVector 的判断与操作
  • C++:动态链接库(dll)的编写,__declspec 用法详解
  • C++ 函数模板
  • RNN工作原理和架构
  • ToolsSet之:TTS及Morse编解码
  • Matplotlib绘制矩阵图,plt.matshow/imshow 与 ax.pcolor(pcolormesh)方法的使用
  • Java集合框架初识
  • 做国外网站需要多少钱/百度推广优化
  • 药理学网站建设方案/十大基本营销方式
  • 安徽建设厅网站官网/seo工具有哪些
  • 做网站用商标吗/外贸营销网站制作
  • 个人做网站多少钱/对seo的理解
  • 网站建设销售技巧/今日小说排行榜百度搜索风云榜