DataGridView绑定DataTable后数据变更如何高效触发界面重绘?
解决DataGridView计算列偶发界面不刷新问题
问题背景
DataGridView绑定了带表达式计算列的DataTable(tblorderspecs),Total列表达式为:
tblorderspecs.Columns("Total").Expression = "Convert(Quantity * Cost - BaseTotal + .499999, 'System.Int64')"
编辑Quantity或Cost列后,DataTable数据已更新,但留在当前行时约50%概率界面不显示最新Total值,调用Refresh()会有0.25秒延迟,切换行时自动刷新无延迟,需实现轻量刷新方案。
解决方案
方案1:监听DataTable变更事件触发轻量刷新
利用DataTable的ColumnChanged事件,在Quantity或Cost列变更时,主动刷新对应行的Total单元格,模拟切换行时的局部重绘逻辑:
Private Sub tblorderspecs_ColumnChanged(sender As Object, e As DataColumnChangeEventArgs) Handles tblorderspecs.ColumnChanged If e.Column.ColumnName = "Quantity" Or e.Column.ColumnName = "Cost" Then Dim rowIndex As Integer = DataGridView1.Rows.Cast(Of DataGridViewRow)().FirstOrDefault(Function(r) r.DataBoundItem Is e.Row)?.Index If rowIndex >= 0 Then Dim totalColIndex As Integer = DataGridView1.Columns("Total").Index DataGridView1.UpdateCellValue(totalColIndex, rowIndex) End If End If End Sub
方案2:手动调用切换行时的核心重绘方法
切换行时DataGridView会通过EndEdit()结束编辑并触发单元格局部重绘,可在编辑完成后手动调用这些方法:
Private Sub DataGridView1_CellEndEdit(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit If DataGridView1.Columns(e.ColumnIndex).ColumnName = "Quantity" Or DataGridView1.Columns(e.ColumnIndex).ColumnName = "Cost" Then DataGridView1.EndEdit() Dim totalColIndex As Integer = DataGridView1.Columns("Total").Index DataGridView1.InvalidateCell(totalColIndex, e.RowIndex) End If End Sub
InvalidateCell仅标记单个单元格重绘,性能远高于全局Refresh(),无明显延迟。
方案3:仅刷新目标单元格/行
直接定位需要更新的区域,调用轻量刷新方法:
- 刷新单个Total单元格:
' 在CellEndEdit事件中调用 Dim totalCol = DataGridView1.Columns("Total") DataGridView1.UpdateCellValue(totalCol.Index, e.RowIndex)
- 刷新整行(多计算列场景):
DataGridView1.UpdateRow(e.RowIndex, e.RowIndex)
这两个方法的内部逻辑和切换行时的自动刷新一致,不会产生全局延迟。
关键说明
- 禁用
DataGridView.Refresh(),该方法会重绘整个控件导致延迟; UpdateCellValue/InvalidateCell为局部操作,性能与切换行自动刷新持平;- 异步数据变更场景下,需通过
Invoke切换到UI线程调用刷新方法。
内容的提问来源于stack exchange,提问作者Luke Krell
相关产品推荐
相关产品推荐

