在排序的 DataTable 中上下移动行作为 DataGridView 的数据源不会更新视图

Moving Rows up and down in a sorted DataTable set as the DataSource of a DataGridView does not update the View

我在网上看过很多类似内容的不同帖子。我的代码正确地移动了行。 这是发生了什么:我按下向上或向下按钮,selected 行相应地移动。
如果我单击刚刚移动的行并尝试将其移回,它会按 DataTable 的 DefaultView 排序顺序移动它,但位置更改不会反映在 DataGridView 中。

如果我 select 从未移动过的行,它会移动它并且 DataGridView 会反映它,但是如果我再次选择同一行并尝试将其移回,则此更改是未反映在视图中,但更新了 DataTable。

我已尝试 ResetBindingsDataGridView.Refresh、重置此作品的数据源:none。

任何人都知道为什么会发生这种情况以及我如何解决它以便每次都反映更改?

 Private Sub UpBtn_Click(sender As Object, e As EventArgs) Handles UpBtn.Click
    MoveUpDataRow(StepDGV.CurrentRow.Index)
End Sub

Private Sub MoveUpDataRow(RowIndex As Integer)
    Dim OriginalStepNumber As Integer
    Dim dv As DataView = StepsData.DefaultView

    OriginalStepNumber = CInt(StepDGV.Rows(RowIndex).Cells("StepIDLS").Value)

    If RowIndex = 0 Then
        'dv(RowIndex - 1)("StepIDLS") = OriginalStepNumber + 1
        'dv(RowIndex)("StepIDLS") = OriginalStepNumber - 1
        exit Sub
    Else

        dv(RowIndex - 1).BeginEdit()
        dv(RowIndex - 1)("StepIDLS") = OriginalStepNumber
        'dv(RowIndex)("StepIDLS") = RowIndex-1
        dv(RowIndex - 1).EndEdit()

        dv(RowIndex).BeginEdit()
        dv(RowIndex)("StepIDLS") = OriginalStepNumber - 1
        'dv(RowIndex)("StepIDLS") = RowIndex-1
        dv(RowIndex).EndEdit()

    End If
    dv.Sort = "StepIDLS ASC"
  '  StepDGV.Rows(RowIndex).Selected = true
    'StepDGV.DataSource = StepsData
    'StepDGV.Refresh()
    StepDGV.ResetBindings()
    StepDGV.Refresh()

End Sub


Private Sub downBtn_Click(sender As Object, e As EventArgs) Handles downBtn.Click
    MoveDownDataRow(StepDGV.CurrentRow.Index)
End Sub

Private Sub MoveDownDataRow(RowIndex As Integer)
    Dim OriginalStepNumber As Integer
    Dim dv As DataView = StepsData.DefaultView

    OriginalStepNumber = CInt(StepDGV.Rows(RowIndex).Cells("StepIDLS").Value)

    If RowIndex = dv.Count - 1 Then
        exit Sub
    Else

        dv(RowIndex + 1).BeginEdit()
        dv(RowIndex + 1)("StepIDLS") = OriginalStepNumber
        dv(RowIndex + 1).EndEdit()

        dv(RowIndex).BeginEdit()
        dv(RowIndex)("StepIDLS") = OriginalStepNumber + 1
        dv(RowIndex).EndEdit()

    End If
    dv.Sort = "StepIDLS ASC"
  '  StepDGV.Rows(RowIndex).Selected = true
    'StepDGV.Refresh()
    'StepDGV.DataSource = StepsData
    'StepDGV.Refresh()
    StepDGV.ResetBindings()
    StepDGV.Refresh()

End Sub[![screenshot of datagridview for visual aid when going through code][1]][1]

由于您有一个排序的 DataView,使用相同的索引引用设置两个连续的值,可能(将会)有未定义的结果,如果您在两个不同的 方向 移动,甚至更多。

方法一:

从当前 DataView 中获取两个 DataRow 的引用然后使用 DataRow 引用更改 Column 的值更简单(并且更实用):即使排序后的 DataView 中的 DataRow 位置发生变化,DataRow 引用也是相同。

您不需要 BeginEdit/EndEdit 单元格值,这些更改会自动传播。

► 在这里,我对两个按钮使用相同的 Button.Click 处理程序,并根据按钮名称确定方向(可以是任何其他适合的名称)。

► 此行:Dim dView = DirectCast(StepDGV.DataSource, DataTable).DefaultView 如果您存储了 DataTable 对象(看起来像),则不需要。
如果是这种情况,当然可以使用您已有的 DataTable 引用。

► 假设您在此之前设置了StepsData.DefaultView.Sort = "StepIDLS ASC"

Private Sub btnMoveRowUpDown_Click(sender As Object, e As EventArgs) Handles UpBtn.Click, downBtn.Click
    If StepDGV.CurrentRow Is Nothing Then Return

    Dim moveUp As Boolean = DirectCast(sender, Button).Name.Equals("UpBtn")

    Dim currentRow As Integer = StepDGV.CurrentCell.RowIndex
    Dim dView = DirectCast(StepDGV.DataSource, DataTable).DefaultView
    Dim rowCurrent = dView(currentRow).Row
    Dim colCurrentValue As Integer = CType(rowCurrent("StepIDLS"), Integer)

    If moveUp Then
        If currentRow = 0 Then Return

        Dim rowPrevious = dView(currentRow - 1).Row
        Dim colPreviousValue As Integer = CType(rowPrevious("StepIDLS"), Integer)
        rowCurrent("StepIDLS") = colPreviousValue
        rowPrevious("StepIDLS") = colCurrentValue
    Else
        If currentRow = StepDGV.NewRowIndex - 1 Then Return

        Dim rowNext = dView(currentRow + 1).Row
        Dim colNextValue As Integer = CType(rowNext("StepIDLS"), Integer)
        rowCurrent("StepIDLS") = colNextValue
        rowNext("StepIDLS") = colCurrentValue
    End If
End Sub

方法二:

您可以执行类似的设置 DataGridView 单元格值。
在这种情况下,您确实需要调用 DataGridView.EndEdit() to notify the change, so it occurs immediately. Otherwise, the value change would be propagated after the focus leaves the CurrentCell

此处的注意事项: 在类似情况下也可能有用(当您必须直接设置 DataGridView 单元格时)。

您还可以注意到,设置 DataRow Colums 值也会更改 DataGridView CurrentRow(而不仅仅是 CurrentCell),而在 DataGridView 中设置单元格的值不会导致CurrentRow要改变,所以你必须自己做,设置:

[DataGridView].CurrentCell = [DataGridView].Rows(currentRow + 1).Cells(currentColumn)

Private Sub btnMoveRowUpDown_Click(sender As Object, e As EventArgs) Handles UpBtn.Click, downBtn.Click
    If StepDGV.CurrentRow Is Nothing Then Return

    Dim moveUp As Boolean = DirectCast(sender, Button).Name.Equals("UpBtn")

    Dim currentRow As Integer = StepDGV.CurrentCell.RowIndex
    Dim currentColumn As Integer = StepDGV.CurrentCell.ColumnIndex
    Dim currentCellValue As Integer = CType(StepDGV("StepIDLS", currentRow).Value, Integer)

    If moveUp Then
        If currentRow = 0 Then Return 
        Dim previousCellValue As Integer = CType(StepDGV("StepIDLS", currentRow - 1).Value, Integer)

        StepDGV.Rows(currentRow).Cells("StepIDLS").Value = previousCellValue
        StepDGV.EndEdit()
        StepDGV.Rows(currentRow - 1).Cells("StepIDLS").Value = currentCellValue
        StepDGV.EndEdit()
        StepDGV.CurrentCell = StepDGV.Rows(currentRow - 1).Cells(currentColumn)
    Else
        If currentRow = StepDGV.NewRowIndex - 1 Then Return 
        Dim nextCellValue As Integer = CType(StepDGV("StepIDLS", currentRow + 1).Value, Integer)

        StepDGV.Rows(currentRow).Cells("StepIDLS").Value = nextCellValue
        StepDGV.EndEdit()
        StepDGV.Rows(currentRow + 1).Cells("StepIDLS").Value = currentCellValue
        StepDGV.EndEdit()
        StepDGV.CurrentCell = StepDGV.Rows(currentRow + 1).Cells(currentColumn)
    End If
End Sub