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

Viewed 275

I've looked online and I've seen a lot of different posts of similar stuff. My code moves the rows correctly. This is what happens: I press either the UP or Down Buttons, the selected rows moves accordingly.
If I click on the Row that I just moved and I try to move it back, it moves it in the DataTable's DefaultView sort order but the position change is NOT reflected in the DataGridView.

If I select a Row I've never moved, it will move it and the DataGridView will reflect it, but once again if I choose that same row and try to move it back, this change is not reflected in the View, but the DataTable is updated.

I've tried to ResetBindings, DataGridView.Refresh, reset the DataSource: none of this works.

Anyone know why this happens and how i can fix it so it reflects the changes every time?

 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]
1 Answers

Since you have a sorted DataView, setting two consecutive values using the same Index reference, may (will) have undefined results, even more if you move in two different directions.

Method 1:

It's simpler (and functional) to get the reference of both DataRows from the current DataView and then change the value of a Column using the DataRow reference: even if the DataRow position in the sorted DataView changes, the DataRow reference is the same.

You don't need to BeginEdit/EndEdit a Cell value, these changes are propagated automatically.

► Here, I'm using the same Button.Click handler for both Buttons and determine the direction based on the Button name (it could be anything else that fits).

► This line: Dim dView = DirectCast(StepDGV.DataSource, DataTable).DefaultView is not necessary if you have stored a DataTable object (as it looks like).
If that's the case, of course use the DataTable reference you already have.

► It's assumed you have set StepsData.DefaultView.Sort = "StepIDLS ASC" before this point.

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

Method 2:

You can do something similar setting the DataGridView Cells values.
In this case, you do need to call DataGridView.EndEdit() to notify the change, so it occurs immediately. Otherwise, the value change would be propagated after the focus leaves the CurrentCell.

The notes here: Bound DataGridView not updating to display information + sorting issues may also be useful in a similar condition (when you have to directly set DataGridView Cells).

You can also notice that setting a DataRow Colums value also changes the DataGridView CurrentRow (not just the CurrentCell), while setting the Value of a Cell in a DataGridView, doesn't cause the CurrentRow to change, so you have to do it yourself, setting:

[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
Related