我有一个使用DataGridView
与DataTable
绑定的BindingSource
并且并非DataGridView
中的所有列都与DataSource
的属性绑定。更具体地说,我有一个用于多选的自定义DataGridViewColumn
,它来自DataGridViewCheckBoxColumn
类,并有一个主复选框,用于控制位于列标题中的其他选项。我的问题是,无论何时调用DataTable.AcceptChanges
,DataGridViewCheckBoxCell
都会恢复其默认值(False),我将丢失之前的选择。有没有人知道一个很好的方法来防止或支持这种行为?
基本上,即使在调用DataTable.AcceptChanges
之后,我仍希望保留该列中的单元格值,因为它们与底层数据源无关。
下面是一些示例代码,可以重现我正在经历的内容。检查选择列中的一些复选框并按Ctrl+S
并注意每次都会丢失这些检查,即使它们没有绑定到特定的DataGridViewColumn
。我意识到这可能是BindingSource
的本质,但我想知道是否有办法绕过这种行为。另外,我想避免编写逻辑来保存在调用AcceptChanges
之前选择的行,然后在AcceptChanges
返回后重置它们。对我来说,如果我们一次在DataGridView
选择了大量的行,这似乎太麻烦了。任何人都有一个更黑暗的想法?
Public Class Form1
Sub New()
InitializeComponent()
Dim dgv As New DataGridView
dgv.Columns.Add(New DataGridViewCheckBoxColumn With {.HeaderText = "Selection"})
dgv.Columns.Add(New DataGridViewTextBoxColumn With {.HeaderText = "ChangeMe", .DataPropertyName = "ChangeMe"})
Controls.Add(dgv) : dgv.Dock = DockStyle.Fill
Dim dt = New DataTable : dt.Columns.Add("ChangeMe", GetType(String))
For Each thing In {"Shoe", "Boat", "Rat"} : dt.Rows.Add(thing) : Next
dgv.DataSource = New BindingSource(dt, Nothing)
Me.KeyPreview = True
AddHandler Me.KeyDown, Sub(sender As Object, e As KeyEventArgs)
If e.Control AndAlso e.KeyCode = Keys.S Then dt.AcceptChanges()
End Sub
End Sub
End Class
这个问题是由于BindingSource
响应BindingSource.ListChanged Event方法而引发ListChangedType.Reset
类型的DataTable.AcceptChanges
引起的。当DataGridView
收到此事件时,它从BindingSource.
重新加载这发生在ProcessListChanged Method(向下滚动到第658行)。
一个可能的解决方法是通过修改密钥处理程序方法来阻止BindingSource
在执行DataTable.AcceptChanges
期间引发事件,如下所示。
AddHandler Me.KeyDown, Sub(sender As Object, e As KeyEventArgs)
If e.Control AndAlso e.KeyCode = Keys.S Then
Dim bs As BindingSource = DirectCast(dgv.DataSource, BindingSource)
bs.RaiseListChangedEvents = False
dt.AcceptChanges()
bs.RaiseListChangedEvents = True
End If
End Sub