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

VB.NET中DataGridView行遍历更新SalesRate不生效问题求助

问题:DataGridView更新SalesRate无法即时生效,需新增行后才显示修改

需求为遍历DataGridView行,基于以下两个条件更新SalesRate列值:

  • 条件1:当前行Qty列数值大于等于数据库返回的PromoQty
  • 条件2:文本标签lblpromo的数值≥0.2,且当前行BD列数值等于数据库返回的BottleDeposit

但修改后无法即时在UI上显示,需新增行后才会更新,移除Try/Catch块后无报错信息。

用户原始代码:

Private Sub DataGridView1_CellValueChanged(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
Try
    If DataGridView1.Rows.Count > 0 Then
        If txtTaxType.Text = "Inclusive" Then
            con = New SqlConnection(cs)
            con.Open()
            Dim ct As String = "select PRate,PQty,BottleDeposit from product where PID=@d1 and POffer='Yes'"
            cmd = New SqlCommand(ct)
            cmd.Parameters.AddWithValue("@d1", Val(DataGridView1.Rows(e.RowIndex).Cells("PID").Value))
            cmd.Connection = con
            rdr = cmd.ExecuteReader()
            If rdr.Read() Then
                Dim BValue = rdr.GetValue(2)
                Dim PromoRate = rdr.GetValue(0)
                Dim PromoQty = Val(rdr.GetValue(1))
                For Each row As DataGridViewRow In DataGridView1.Rows
                    If Val(DataGridView1.Rows(e.RowIndex).Cells("Qty").Value) >= PromoQty Then
                        DataGridView1.Rows(e.RowIndex).Cells("SalesRate").Value = PromoRate
                    End If
                    If lblpromo.Text >= 0.2 And Val(DataGridView1.Rows(e.RowIndex).Cells("BD").Value) = BValue Then
                        row.Cells("SalesRate").Value = PromoRate
                    End If
                Next
            End If
            con.Close()
Catch ex As Exception
    MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

问题分析

  1. 遍历逻辑错误:For Each循环中,第一个条件始终只操作触发事件的e.RowIndex行,而非当前遍历的row;第二个条件里的BD值也错误引用了触发行的数据,导致大部分行的更新逻辑未正确执行。
  2. UI未主动刷新:修改单元格值后,DataGridView可能未即时重绘,需手动触发刷新。
  3. 资源未正确释放:数据库连接、命令、读取器未用Using语句管理,存在资源泄漏风险。
  4. 类型转换不严谨:Val()函数转换数值可能导致意外结果,建议使用强类型转换并添加验证。
  5. 条件逻辑冗余:两个独立的If条件可能导致值被重复覆盖,需明确逻辑优先级。

修复后的代码

Private Sub DataGridView1_CellValueChanged(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
    ' 排除无效行(如新增行的空行)
    If e.RowIndex < 0 OrElse DataGridView1.Rows(e.RowIndex).IsNewRow Then Return
    If DataGridView1.Rows.Count = 0 Then Return
    If txtTaxType.Text <> "Inclusive" Then Return

    ' 使用Using自动管理数据库资源
    Using con As New SqlConnection(cs)
        con.Open()
        Dim ct As String = "select PRate,PQty,BottleDeposit from product where PID=@d1 and POffer='Yes'"
        Using cmd As New SqlCommand(ct, con)
            ' 强类型转换PID,避免Val()的问题
            Dim pid As Integer
            If Not Integer.TryParse(DataGridView1.Rows(e.RowIndex).Cells("PID").Value.ToString(), pid) Then
                MessageBox.Show("无效的PID值", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                Return
            End If
            cmd.Parameters.AddWithValue("@d1", pid)

            Using rdr As SqlDataReader = cmd.ExecuteReader()
                If rdr.Read() Then
                    ' 强类型读取数据库返回值
                    Dim promoRate As Decimal = CDec(rdr("PRate"))
                    Dim promoQty As Integer = CInt(rdr("PQty"))
                    Dim bValue As Decimal = CDec(rdr("BottleDeposit"))

                    ' 解析lblpromo的数值
                    Dim promoValue As Decimal
                    If Not Decimal.TryParse(lblpromo.Text, promoValue) Then
                        MessageBox.Show("lblpromo的数值格式无效", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                        Return
                    End If

                    ' 遍历所有行,修正逻辑:使用当前遍历的row
                    For Each row As DataGridViewRow In DataGridView1.Rows
                        If row.IsNewRow Then Continue For ' 跳过新增行

                        Dim qty As Integer
                        If Not Integer.TryParse(row.Cells("Qty").Value.ToString(), qty) Then Continue For

                        Dim bdValue As Decimal
                        If Not Decimal.TryParse(row.Cells("BD").Value.ToString(), bdValue) Then Continue For

                        ' 条件1:当前行Qty≥PromoQty,更新SalesRate
                        If qty >= promoQty Then
                            row.Cells("SalesRate").Value = promoRate
                        End If

                        ' 条件2:lblpromo≥0.2且当前行BD=BValue,更新SalesRate
                        If promoValue >= 0.2D AndAlso bdValue = bValue Then
                            row.Cells("SalesRate").Value = promoRate
                        End If
                    Next

                    ' 手动刷新DataGridView,确保UI即时更新
                    DataGridView1.Refresh()
                End If
            End Using
        End Using
    End Using
End Sub

关键修复点说明

  • 修正遍历逻辑:所有条件判断均使用当前遍历的row对象,而非固定的触发事件行。
  • 添加UI刷新:遍历完成后调用DataGridView1.Refresh()强制重绘UI,确保修改即时显示。
  • 资源管理:用Using语句包裹SqlConnection、SqlCommand、SqlDataReader,自动释放资源。
  • 强类型转换:使用Integer.TryParse()、Decimal.TryParse()进行类型转换,添加有效性验证,避免转换错误。
  • 跳过无效行:排除新增行(IsNewRow)和数值无效的行,避免逻辑异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 19:01:19