You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ComboBox值变更时终止DataGridView的异步For Each循环

解决方案

要解决ComboBox值变更时旧循环仍在运行的问题,核心是引入**取消令牌(CancellationToken)**来管理异步任务的生命周期,确保旧任务能被立即终止,新任务可以马上启动。

步骤1:声明取消令牌源字段

在窗体类中添加一个CancellationTokenSource字段,用于控制当前正在运行的查询任务:

Private currentCts As CancellationTokenSource

步骤2:处理ComboBox值变更事件

在ComboBox的SelectedIndexChanged(或TextChanged)事件中,先取消旧任务,再启动新的查询任务:

Private Sub cbpayment_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbpayment.SelectedIndexChanged
    ' 终止并释放旧的取消令牌源
    currentCts?.Cancel()
    currentCts?.Dispose()
    
    ' 创建新的取消令牌源
    currentCts = New CancellationTokenSource()
    
    ' 启动新的异步查询任务
    _ = dgvquery(currentCts.Token)
End Sub

步骤3:修改异步查询方法

重构原dgvquery方法,加入取消检查、资源安全管理和UI线程同步:

Async Function dgvquery(ct As CancellationToken) As Task
    Try
        ' 获取去重的客户列表(使用Using块自动释放数据库资源)
        Dim dtcust As New DataTable
        Using conn As New MySqlConnection("你的数据库连接字符串")
            conn.Open()
            Using da As New MySqlDataAdapter("SELECT DISTINCT Customer FROM tbtransaction", conn)
                da.Fill(dtcust)
            End Using
        End Using

        For Each drowcust As DataRow In dtcust.Rows
            ' 检查任务是否被取消,若取消则终止循环
            ct.ThrowIfCancellationRequested()

            Dim cust As String = drowcust.Item("Customer").ToString()
            ' 查询当前客户+支付方式的数据(参数化查询避免SQL注入)
            Dim ds As New DataSet
            Using conn As New MySqlConnection("你的数据库连接字符串")
                conn.Open()
                Using da As New MySqlDataAdapter("SELECT * FROM tbtransaction WHERE Customer = @Cust AND Payment = @Payment", conn)
                    da.SelectCommand.Parameters.AddWithValue("@Cust", cust)
                    da.SelectCommand.Parameters.AddWithValue("@Payment", cbpayment.Text)
                    da.Fill(ds)
                End Using
            End Using

            ' 在UI线程更新DataGridView(异步方法需切换回UI线程)
            If dgvtransaction.InvokeRequired Then
                dgvtransaction.Invoke(Sub()
                                          dgvtransaction.DataSource = ds.Tables(0)
                                      End Sub)
            Else
                dgvtransaction.DataSource = ds.Tables(0)
            End If

            ' 延迟10秒,同时监听取消请求
            Await Task.Delay(10000, ct)
        Next
    Catch ex As OperationCanceledException
        ' 任务被取消,无需额外处理
    Catch ex As Exception
        ' 处理数据库异常等错误
        MessageBox.Show($"错误:{ex.Message}")
    End Try
End Function

关键优化点说明

  • 取消机制:通过CancellationTokenSource实现任务的即时终止,每次ComboBox值变化时,旧任务会在下次循环检查或延迟时立即退出。
  • 资源安全:使用Using块管理数据库连接和数据适配器,避免连接泄漏。
  • SQL注入防护:替换原字符串拼接的SQL语句为参数化查询,提升安全性。
  • UI线程同步:异步方法中更新DataGridView时,通过Invoke确保操作在UI线程执行,避免跨线程错误。

内容的提问来源于stack exchange,提问作者Selikur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 12:44:54