VSTO 开发 EXCEL 委托与多线程的极简示例

文章描述了一个在开发VSTOExcel加载项时遇到的问题,即由于网络延迟导致UI卡顿。作者尝试了VB.NET的异步操作但未解决问题,因为VB.NET的异步本质上仍是单线程。最终,通过引入委托和多线程,成功解决了UI阻塞问题。此外,文章还提到了单线程异步和多线程异步的适用场景,强调了根据任务类型选择合适的方法以优化性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

VSTO 开发 EXCEL 委托与多线程的极简示例

问题

这几天做 excel 加载项时遇到一个问题,对话框弹窗显示后,需要等待网络数据的返回来填充 ListBox 控件,由于网络延迟问题,整个窗体连带 Excel 一起白屏卡顿 5-10秒,体验感极差。

解决

这个问题其实在网络编程中是最常见的,通常都是采用 post 异步操作。于是我在 vb 中引用了 Task 异步载入数据,但问题依旧。查阅资料后原来是 vb.net 异步是单线程的,IO 繁忙阻塞了后续代码的执行。在 郑广学 老师的指点下,采用 vb 委托回调的概念,果然解决了这个痛点。

步骤

  1. 打开 Visual Studio 2017/2019/2021
  2. 创建一个 Excel VSTO 外接程序的新项目
  3. 添加一个 功能区(可视化设计器),编译器创建 Ribbon1.vb
  4. 点击工具面板增加一个按钮
  5. 添加一个 Windows 窗体,在窗体里添加 RichText 控件

代码

代码文件 Ribbon1.vb,设置按钮弹窗响应

Imports Microsoft.Office.Tools.Ribbon
Public Class Ribbon1
    Private Sub Button1_Click(sender As Object, e As RibbonControlEventArgs) Handles Button1.Click
        Dim DW As New Form1
        DW.Show()
    End Sub
End Class

代码文件 Form1.vb, 声明委托、多线程、回调

Public Class Form1

    Public Delegate Sub UpdateText(ByVal txt As String)     '定义一个空委托,只有名字和参数
    Private LoadText As UpdateText              '声明一个委托类型变量

    Private Sub TextSet(ByVal txt As String)    '定义函数,将参数 txt 存入 RichText 控件中
        Me.RichTextBox1.Text = txt
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        Dim thId1 As Integer = Threading.Thread.CurrentThread.ManagedThreadId
        LoadText = AddressOf TextSet    '当函数载入内存后,将其指针存到变量 LoadText
        Dim sthread As New Threading.Thread(         '创建第二线程并载入匿名函数
            Sub()
                Dim thId2 As Integer = Threading.Thread.CurrentThread.ManagedThreadId
                Threading.Thread.Sleep(5000)        '模拟网络延迟 5 秒
                Dim res As String = $"当前线程号:{thId2},来自 Web 的问候"     '读到网络数据
                Me.Invoke(LoadText, res)            '在第二线程中执行回调函数
            End Sub
         )
        sthread.Start()
        RichTextBox1.Text = $"当前线程号:{thId1},数据载入中,请稍候..."
    End Sub

End Class

找到原因了,单线程异步也可以避免阻塞,但是我把 Task.Delay() 时间设置的太短,此时载入窗口的主线程任务还没完成,造成阻塞。

Imports System.Threading.Tasks
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        Dim thId1 As Integer = Threading.Thread.CurrentThread.ManagedThreadId
        Dim p As Task = LoadWebTextAsync()
        RichTextBox1.Text = $"当前线程号:{thId1},数据载入中,请稍后..."
    End Sub
    Async Function LoadWebTextAsync() As Task
        Await Task.Delay(5000)
        Dim thId2 As Integer = Threading.Thread.CurrentThread.ManagedThreadId
        RichTextBox1.Text = $"当前线程号:{thId2},来自 Web 的问候!"
    End Function
End Class

使用单线程异步和多线程异步使用原则:IO 密集型,如读取网络数据,此时 CPU 闲置率高,用单线程异步主要不产生阻塞,程序性能更高。多线程异步适合 计算密集型,如处理一百万行数据,此时 CPU 占用率高,启用多核心的 CPU 可以提高程序性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yxp_xa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值