【问题标题】:datagridview last programmatically changed cell does not get included in changedrowsdatagridview 最后以编程方式更改的单元格未包含在 changedrows 中
【发布时间】:2021-06-21 06:49:01
【问题描述】:

VB.net 应用程序以编程方式更改数据网格视图中的值。这些值都是应有的,但保存例程(dtShipments 是作为 datagridview 源的数据表) 将 dtChanges 调暗为 DataTable = dtShipments.getchanges() 如果不止一个发生了变化,dtChanges 总是会丢失最后一行。

在更改单元格值的例程中,我尝试过 DatagridView1.EndEdit 和 DatagridView1.CommitEdit,但行为是相同的。我什至尝试添加一个 SendKeys.Send(vbTab) 行,因为在手动进行更改时按 Tab 键足以让所有更改显示在 .GetChanges 中。

我错过了什么?

每个请求的代码:

Private Sub btnAssign_Click(sender As Object, e As EventArgs) Handles btnAssign.Click
        strModErr = "Form1_btnAssign_Click"
        Dim sTruck As String = ""
        Try
            sTruck = Me.DataGridView2.SelectedCells(0).Value.ToString
            For Each row As DataGridViewRow In DataGridView1.SelectedRows
                row.Cells("Truck").Value = sTruck                
            Next
            DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
        Catch ex As Exception
            WriteErrorToLog(Err.Number, strModErr + " - " + Err.Description)
        End Try
    End Sub
Private Function SaveChanges() As Boolean
        strModErr = "Form1_SaveChanges"
        Dim Conn As New SqlConnection(My.Settings.SQLConnectionString)
        Dim sSQL As String = "UPDATE fs_Shipments SET Truck = @Truck, Stop = @Stop WHERE SalesOrder = @SO"
        Dim cmd As New SqlCommand(sSQL, Conn)
        Dim sSO, sTruck As String
        Dim iStop As Integer = 0
        Try
            DataGridView1.EndEdit()
            DataGridView1.ClearSelection()
            Dim dtChanges As DataTable = dtShipments.getchanges()       'DataRowState.Modified

            If Not dtChanges Is Nothing Then
                Conn.Open()

                For Each row As DataRow In dtChanges.Rows
                    sSO = row("SalesOrder").ToString
                    sTruck = row("Truck").ToString
                    iStop = CInt(row("Stop").ToString)
                    With cmd.Parameters
                        .Clear()
                        .AddWithValue("@SO", sSO)
                        .AddWithValue("@Truck", sTruck)
                        .AddWithValue("@Stop", iStop)
                    End With
                    cmd.ExecuteNonQuery()
                Next
            End If
            Return True
        Catch ex As Exception
            WriteErrorToLog(Err.Number, strModErr + " - " + Err.Description)            
            Return False
        End Try
    End Function

【问题讨论】:

  • DataGridView.Rows 集合中的每一行都有一个DataBoundItem 属性。获取该引用并更改其列的值。无论如何,您应该在第一次加载 DataTable 时调用 AcceptChanges(),否则状态已经从一开始就设置好了,所以状态可能看起来没有改变,GetChanges() 不会返回一个或多个在其视图中未更改状态的行集合中的行。
  • 请注意,DataRowState.AddedDataRowState.Modified
  • 你能提供一个重现这个的代码示例吗?我无法重现您所描述的内容。
  • 根据请求添加的代码。

标签: vb.net datagridview


【解决方案1】:

我不能 100% 确定为什么会发生这种情况。该问题似乎特定于用户“选择”第一个网格中的单元格,然后调用SaveChanges 代码“之前”用户在第一个网格中进行了另一个选择。换句话说,如果用户在网格 1 中“选择”行以将卡车“分配”到,那么,“在”“选定”单元格已被所选卡车填充之后,用户在网格 1 中选择其他单元格网格 1,然后调用保存更改代码。在这种情况下,代码按预期工作。

我提交更改的所有尝试都失败了或引入了其他问题。我相信这很大程度上与网格SelectedRows 集合有关。恕我直言,这看起来像是一种设置单元格值的冒险方法,我认为更用户友好的方法可能是在每一行上添加一个复选框并将卡车值分配给选中的行。但这是一种意见。

无论如何,经过多次尝试,我想出的解决方案只是进一步证明了为什么使用BindingSource 在许多方面都很有用。在这种情况下,DataTable 似乎没有随着最后一次单元格更改而更新。同样,我不确定“为什么”会这样,但是由于它似乎可以使用 BindingSource,我只能假设它与 DataTable 本身有关。换句话说,在执行“保存”代码之前,我们可以调用表的AcceptChanges 方法,但是我们会丢失这些更改。所以这不是一个选择。

为了帮助,下面是一个完整的(无绒毛)示例。将来,我强烈建议您删除与问题无关的代码部分。例如,所有将更改保存到数据库的代码对于问题来说都是多余的……所以删除它。您在问题中添加的不必要代码越多,只会增加“忽略”问题的 SO 用户数量。如果您发布最小、完整和有效的代码来重现问题,以便用户可以简单地复制和粘贴,而无需添加额外的代码或删除不必要的代码,这将增加您获得良好答案的机会。只是为未来做好准备。

下面的解决方案只是添加了一个BindingSourceBindingSource’s DataSourceDataTable dtShipments 然后 BindingSource 使用 DataSourceDataGridView1。然后在SaveChanges方法中,“之前”代码调用dtShipment.GetChanges()方法,我们将调用BindingSources.ResetBinding()方法,它应该完成对底层数据源的编辑,在这种情况下是DataTabledtShipments.

如果您创建新的 VS-VB winforms 解决方案,请将两 (2) 个网格和两 (2) 个按钮拖放到表单上,如下所示,然后将按钮名称更改为“btnAssign”和“btnApplyChanges”。分配按钮会将网格 2 中的选定卡车添加到网格 1 中的选定行。应用更改按钮只是重置绑定源并显示一个消息框,其中包含在dtShipmentsDataTable 中更改的行数。需要注意的是,代码调用dtShipments.AcceptChanges() 方法来清除更改。否则,代码将更新已经进行的更改。

Dim dtShipments As DataTable
Dim dtTrucks As DataTable
Dim shipBS As BindingSource

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  dtShipments = GetShipmentsDT()
  shipBS = New BindingSource()
  shipBS.DataSource = dtShipments
  dtTrucks = GetTrucksDT()
  dtShipments.AcceptChanges()
  DataGridView1.DataSource = shipBS
  DataGridView2.DataSource = dtTrucks
End Sub

Private Function GetShipmentsDT() As DataTable
  Dim dt = New DataTable()
  dt.Columns.Add("ID", GetType(String))
  dt.Columns.Add("Truck", GetType(String))
  dt.Rows.Add(1)
  dt.Rows.Add(2)
  dt.Rows.Add(3)
  dt.Rows.Add(4)
  Return dt
End Function

Private Function GetTrucksDT() As DataTable
  Dim dt = New DataTable()
  dt.Columns.Add("Truck", GetType(String))
  For index = 1 To 10
    dt.Rows.Add("Truck" + index.ToString())
  Next
  Return dt
End Function

Private Sub btnAssign_Click(sender As Object, e As EventArgs) Handles btnAssign.Click
  Dim sTruck = DataGridView2.SelectedCells(0).Value.ToString
  'Dim drv As DataRowView
  For Each row As DataGridViewRow In DataGridView1.SelectedRows
    'drv = row.DataBoundItem
    'drv("Truck") = sTruck
    row.Cells("Truck").Value = sTruck
  Next
  'DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
  'shipBS.ResetBindings(True)
  'DataGridView1.CurrentCell = DataGridView1.Rows(0).Cells(0)
End Sub

Private Function SaveChanges() As Boolean
  Try
    shipBS.ResetBindings(True)
    Dim dtChanges As DataTable = dtShipments.GetChanges()
    If (dtChanges IsNot Nothing) Then
      MessageBox.Show("There are " & dtChanges.Rows.Count & " rows changed in the data table")
      ' update sql DB
      dtShipments.AcceptChanges()
    End If
    Return True
  Catch ex As Exception
    Return False
  End Try
End Function

Private Sub btnApplyChanges_Click(sender As Object, e As EventArgs) Handles btnApplyChanges.Click
  Dim ChangesMade As Boolean
  ChangesMade = SaveChanges()
End Sub

最后,由于您使用的是 VB……我强烈建议您将“Strict”选项设置为“ON”。当此选项打开时,它将标记您可能遗漏的可能错误。要为所有未来的 VB 解决方案执行此操作,请打开 VS,关闭任何可能打开的解决方案,然后转到工具->选项->项目和解决方案->VB 默认值,然后将“Option Strict”设置为“On”。默认设置为关闭。

我希望这有意义并有所帮助。

【讨论】:

  • 谢谢约翰!完美运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-23
  • 1970-01-01
相关资源
最近更新 更多