VB2010中DataGridView调用DataTable.AcceptChanges后丢失单元格格式问题
我正好碰到过好几个开发者遇到这个VB2010里的坑,咱们来拆解一下问题和解决办法:
问题根源
当你调用DataTable.AcceptChanges()时,它会把DataTable中所有行的状态重置为Unchanged,同时触发DataGridView的重新绑定逻辑。而你给DataGridView单元格设置的自定义格式(比如字体颜色、背景色、对齐方式等),都是存储在DataGridView的单元格实例里的,并非和DataTable的行数据绑定在一起。重新绑定后,这些临时存储的格式就会被清空,导致看起来格式丢失了。
解决方案
方案1:提前保存单元格格式,执行AcceptChanges后恢复
如果你的单元格格式是逐个设置的(每个单元格可能不一样),可以先遍历所有单元格把格式存起来,执行完AcceptChanges()再恢复回去。
示例代码:
' 第一步:保存所有非新增行的单元格格式 Dim cellFormatCache As New Dictionary(Of String, DataGridViewCellStyle) For Each row As DataGridViewRow In DataGridView1.Rows ' 跳过新增行 If Not row.IsNewRow Then For Each cell As DataGridViewCell In row.Cells ' 用行索引+列索引作为唯一标识 Dim cacheKey As String = $"{row.Index}_{cell.ColumnIndex}" ' 复制单元格的样式对象,避免引用问题 cellFormatCache(cacheKey) = New DataGridViewCellStyle(cell.Style) Next End If Next ' 执行AcceptChanges操作 YourDataTable.AcceptChanges() ' 第三步:恢复单元格格式 For Each row As DataGridViewRow In DataGridView1.Rows If Not row.IsNewRow Then For Each cell As DataGridViewCell In row.Cells Dim cacheKey As String = $"{row.Index}_{cell.ColumnIndex}" If cellFormatCache.ContainsKey(cacheKey) Then cell.Style = cellFormatCache(cacheKey) End If Next End If Next
方案2:将格式与DataRow绑定,刷新后从DataRow读取
如果你的格式是和行数据关联的(比如某行数据满足条件就变红),可以把格式信息存在对应DataRow的Tag属性里,这样即使重新绑定,也能从DataRow里读取格式并应用。
示例代码:
' 设置单元格格式时,同时把格式存到DataRow的Tag中 For Each row As DataGridViewRow In DataGridView1.Rows If Not row.IsNewRow Then Dim drv As DataRowView = DirectCast(row.DataBoundItem, DataRowView) ' 假设这里根据数据设置格式 If Convert.ToInt32(drv("Amount")) > 1000 Then row.DefaultCellStyle.ForeColor = Color.Red ' 把格式存到DataRow的Tag里 drv.Row.Tag = New DataGridViewCellStyle(row.DefaultCellStyle) End If End If Next ' 执行AcceptChanges YourDataTable.AcceptChanges() ' 从DataRow的Tag中恢复格式 For Each row As DataGridViewRow In DataGridView1.Rows If Not row.IsNewRow Then Dim drv As DataRowView = DirectCast(row.DataBoundItem, DataRowView) If drv.Row.Tag IsNot Nothing AndAlso TypeOf drv.Row.Tag Is DataGridViewCellStyle Then row.DefaultCellStyle = DirectCast(drv.Row.Tag, DataGridViewCellStyle) End If End If Next
方案3:针对整列统一格式,保存列的样式
如果你的格式是整列统一设置的(比如某列所有单元格都是居中对齐),可以把列的默认样式存在列的Tag属性里,刷新后直接恢复列的样式即可,不用遍历单元格。
示例代码:
' 初始化时保存列的默认样式 For Each col As DataGridViewColumn In DataGridView1.Columns col.Tag = New DataGridViewCellStyle(col.DefaultCellStyle) Next ' 执行AcceptChanges YourDataTable.AcceptChanges() ' 恢复列的默认样式 For Each col As DataGridViewColumn In DataGridView1.Columns If col.Tag IsNot Nothing AndAlso TypeOf col.Tag Is DataGridViewCellStyle Then col.DefaultCellStyle = DirectCast(col.Tag, DataGridViewCellStyle) End If Next
额外提示
其实如果只是想切换编辑模式,设置DataGridView1.ReadOnly = True就足够阻止用户编辑了,不一定需要调用AcceptChanges()。只有当你需要提交所有未确认的行修改(把行状态从Added/Modified改成Unchanged)时,才需要调用这个方法——如果不是必须的,可以跳过这个步骤,自然就不会丢失格式了。
内容的提问来源于stack exchange,提问作者sinDizzy

