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

