【问题标题】:Keep DataGridView BindingSource From Updating a Particular Column's Cell Values阻止 DataGridView BindingSource 更新特定列的单元格值
【发布时间】:2019-03-21 19:29:43
【问题描述】:

我有一个DataGridView,它使用BindingSource 绑定到DataTable,并不是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

【问题讨论】:

    标签: vb.net winforms datagridview datatable bindingsource


    【解决方案1】:

    该问题是由BindingSource 引发ListChangedType.Reset 类型的BindingSource.ListChanged Event 以响应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
    

    【讨论】:

    • 我很喜欢这个,但我的困境是在我当前的项目中AcceptChanges 在另一个类中被调用。我想我可以让该类在调用 AcceptChanges 之前和之后引发一个事件,以提示 UI 层侦听这些事件并启用/禁用 BindingSource 上的 RaiseListChangedEvents,虽然看起来很笨重。如果我的声誉更高,我会碰到这个,谢谢。
    • @lizaardman04,该信息应包含在您的问题中。具体来说,repo 代码并不能反映您的实际情况。如果对AcceptChanges 的调用在另一个类中,您的用户界面中的什么操作会导致它执行?你不能用上面所示的类似逻辑来包装那个动作吗?如果不是,请显示BindingSource.DataSource 属性如何引用底层DataTableDataTable 是否起源于这个其他类?简而言之,如果您希望获得特定的解决方案,您需要提供所有可能影响建议解决方案的信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-30
    相关资源
    最近更新 更多