VB.Net WinForm用Async/Await实现RadGridView数据导入及进度条更新
实现方案
核心改造思路
- 将按钮点击事件改为异步事件处理程序,用
Async/Await语法实现非阻塞调用 - 拆分逻辑:耗时的数据库插入操作全部放在后台线程执行,UI线程只负责控件状态更新、进度展示
- 采用
IProgress(Of T)实现线程安全的进度条更新,无需手动处理跨线程控件调用 - 导入过程中禁用提交按钮、显示进度条,避免重复提交操作
完整修改代码
1. 窗体Load事件(无强制改动,可选异步加载数据避免启动卡UI)
Private Async Sub Import_Payroll_Review_Load(sender As Object, e As EventArgs) Handles Me.Load ' 可选:把数据加载也改为异步,避免窗体启动时卡顿 rgImport.DataSource = Await Task.Run(Function() DataAPI.HR_Payroll_Import_GetData()) ProgressBar1.Minimum = 0 ProgressBar1.Maximum = 100 ProgressBar1.Visible = False End Sub
如果不需要异步加载数据,原Load代码可以直接保留。
2. 异步提交按钮事件
Private Async Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click Select Case MsgBox("Are you sure you are ready to import?", MsgBoxStyle.YesNo, "Import Records") Case MsgBoxResult.Yes ' 先更新UI状态,防止重复操作 btnSubmit.Enabled = False Label1.Text = "正在导入数据,请稍候..." ProgressBar1.Value = 0 ProgressBar1.Visible = True ' 获取待导入数据,若该接口耗时也可以包到Task.Run里 Dim dt As DataTable = DataAPI.HR_Payroll_Import_GetRecordsToImport() Dim iTotalRows As Long = dt.Rows.Count Dim successCount As Long = 0 Dim failCount As Long = 0 ' 声明进度更新回调,自动在UI线程执行 Dim progress = New Progress(Of Integer)(Sub(percent) ProgressBar1.Value = percent End Sub) ' 后台执行插入逻辑 Await Task.Run(Sub() Dim currentIndex As Long = 0 For Each dr As DataRow In dt.Rows Dim insertResult As Boolean If dr("AfterHours") = 0 Then insertResult = DataAPI.HR_Payroll_TimeCards_Insert(dr) Else insertResult = DataAPI.HR_Payroll_TimeCards_Insert_Double(dr) End If ' 统计结果 If insertResult Then successCount += 1 Debug.Print("Inserted Row into TimeCard.Current") Else failCount += 1 Debug.Print("Failed to insert row into TimeCard.Current") End If ' 计算并上报进度 currentIndex += 1 Dim percent = CInt(Math.Truncate(currentIndex * 100 / iTotalRows)) progress.Report(percent) Next End Sub) ' 全部完成后更新UI ProgressBar1.Visible = False Label1.Text = "请核查下方展示的记录" btnSubmit.Enabled = True MsgBox($"导入完成:成功{successCount}条,失败{failCount}条", vbInformation, "操作完成") Case Else Exit Sub End Select End Sub
关键说明
- 异步事件处理程序用
Async Sub声明是.NET的规范用法,仅可用于事件处理场景,其余异步方法请返回Task/Task(Of T) Progress(Of T)的回调会自动封送到UI线程执行,不需要手动调用Invoke处理跨线程控件访问问题- 若你的
DataAPI提供了对应插入方法的异步实现(比如InsertAsync/Insert_DoubleAsync),可以把Task.Run里的同步调用替换为Await异步调用,后台线程资源占用会更低
内容的提问来源于stack exchange,提问作者Eric Lindros
相关产品推荐
相关产品推荐

