datagridview 最后一个以编程方式更改的单元格未包含在更改的行中
datagridview last programmatically changed cell does not get included in changedrows
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
我不是 100% 确定为什么会这样。该问题似乎特定于用户“选择”第一个网格中的单元格,然后调用 SaveChanges
代码“之前”用户在第一个网格中进行了另一个选择。换句话说,如果用户在网格 1 中“选择”要将卡车“分配”到的行,则“在”“选定”单元格已被选定卡车填满后,然后,用户在网格 1 中选择其他单元格网格 1,然后调用保存更改代码。在这种情况下,代码会按预期工作。
我所有提交更改的尝试都失败了或引入了其他问题。我相信这在很大程度上与网格 SelectedRows
集合有关。恕我直言,这看起来是一种设置单元格值的冒险方式,我认为更 user-friendly 的方法可能是在每一行上添加一个复选框并将卡车值分配给选中的行。但这是一个意见。
无论如何,经过多次尝试,我想出的解决方案只是进一步证明了为什么使用 BindingSource
在很多方面都很有用。在这种情况下,DataTable
似乎没有随着最后一次单元格更改而更新。同样,我不确定这是“为什么”,但是由于它似乎可以使用 BindingSource
,我只能假设它与 DataTable
本身有关。换句话说,在执行“Save”代码之前,我们可以调用 tables AcceptChanges
方法,但是我们会丢失这些更改。所以那不是一个选择。
为了提供帮助,下面是一个完整的 (no-fluff) 示例。将来,我强烈建议您提取与问题无关的代码部分。例如,所有将更改保存到数据库的代码相对于问题都是多余的……因此将其删除。添加到问题中的不必要代码越多,只会增加“忽略”该问题的 SO 用户的数量。如果您 post 重现问题的最小、完整和有效的代码,以便用户可以简单地复制和粘贴而无需添加附加代码或删除不必要的代码,将会增加您获得好的答案的机会。只是为未来提个醒。
下面的解决方案只是添加了一个BindingSource
。 BindingSource’
s DataSource
就是DataTable
dtShipments
然后BindingSource
就用了DataSource
到DataGridView1
。然后在 SaveChanges
方法中,“在”代码调用 dtShipment.GetChanges()
方法之前,我们将调用 BindingSources.ResetBinding()
方法来完成对基础数据源的编辑,在本例中 DataTable
dtShipments.
如果您创建一个新的 VS-VB winforms 解决方案,请将两 (2) 个网格和两 (2) 个按钮拖放到窗体上,如下所示,然后将按钮名称更改为“btnAssign”和“btnApplyChanges”。 ”分配按钮会将网格二中的选定卡车添加到网格一中的选定行。应用更改按钮只是重置绑定源并显示一个消息框,其中包含 dtShipments
DataTable
中更改的行数。应该注意的是,代码调用 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... 我强烈建议您将“严格”选项设置为“开”。当此选项打开时,它将标记您可能遗漏的可能错误。要为所有未来的 VB 解决方案执行此操作,请打开 VS,关闭所有可能打开的解决方案,然后转到工具->选项->项目和解决方案->VB 默认值,然后设置“Option Strict ”到“开”。默认设置为关闭。
我希望这是有道理的并且有所帮助。
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
我不是 100% 确定为什么会这样。该问题似乎特定于用户“选择”第一个网格中的单元格,然后调用 SaveChanges
代码“之前”用户在第一个网格中进行了另一个选择。换句话说,如果用户在网格 1 中“选择”要将卡车“分配”到的行,则“在”“选定”单元格已被选定卡车填满后,然后,用户在网格 1 中选择其他单元格网格 1,然后调用保存更改代码。在这种情况下,代码会按预期工作。
我所有提交更改的尝试都失败了或引入了其他问题。我相信这在很大程度上与网格 SelectedRows
集合有关。恕我直言,这看起来是一种设置单元格值的冒险方式,我认为更 user-friendly 的方法可能是在每一行上添加一个复选框并将卡车值分配给选中的行。但这是一个意见。
无论如何,经过多次尝试,我想出的解决方案只是进一步证明了为什么使用 BindingSource
在很多方面都很有用。在这种情况下,DataTable
似乎没有随着最后一次单元格更改而更新。同样,我不确定这是“为什么”,但是由于它似乎可以使用 BindingSource
,我只能假设它与 DataTable
本身有关。换句话说,在执行“Save”代码之前,我们可以调用 tables AcceptChanges
方法,但是我们会丢失这些更改。所以那不是一个选择。
为了提供帮助,下面是一个完整的 (no-fluff) 示例。将来,我强烈建议您提取与问题无关的代码部分。例如,所有将更改保存到数据库的代码相对于问题都是多余的……因此将其删除。添加到问题中的不必要代码越多,只会增加“忽略”该问题的 SO 用户的数量。如果您 post 重现问题的最小、完整和有效的代码,以便用户可以简单地复制和粘贴而无需添加附加代码或删除不必要的代码,将会增加您获得好的答案的机会。只是为未来提个醒。
下面的解决方案只是添加了一个BindingSource
。 BindingSource’
s DataSource
就是DataTable
dtShipments
然后BindingSource
就用了DataSource
到DataGridView1
。然后在 SaveChanges
方法中,“在”代码调用 dtShipment.GetChanges()
方法之前,我们将调用 BindingSources.ResetBinding()
方法来完成对基础数据源的编辑,在本例中 DataTable
dtShipments.
如果您创建一个新的 VS-VB winforms 解决方案,请将两 (2) 个网格和两 (2) 个按钮拖放到窗体上,如下所示,然后将按钮名称更改为“btnAssign”和“btnApplyChanges”。 ”分配按钮会将网格二中的选定卡车添加到网格一中的选定行。应用更改按钮只是重置绑定源并显示一个消息框,其中包含 dtShipments
DataTable
中更改的行数。应该注意的是,代码调用 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... 我强烈建议您将“严格”选项设置为“开”。当此选项打开时,它将标记您可能遗漏的可能错误。要为所有未来的 VB 解决方案执行此操作,请打开 VS,关闭所有可能打开的解决方案,然后转到工具->选项->项目和解决方案->VB 默认值,然后设置“Option Strict ”到“开”。默认设置为关闭。
我希望这是有道理的并且有所帮助。