I want to develop an up/down row feature inside a binded datagridview (I found some examples but only with unbinded datagridview)
Here's my code:
Private Sub dtgHashtagDescripteurs_KeyUp(ByVal sender As Object, ByVal e As KeyEventArgs) Handles dtgHashtagDescripteurs.KeyUp
Dim tblUpdatedDataSource As DataTable
If e.KeyCode.Equals(Keys.Up) Then
Dim intSelectedRowIndex As Integer = dtgHashtagDescripteurs.CurrentCell.RowIndex
If intSelectedRowIndex = 0 Then
Exit Sub
Else
tblUpdatedDataSource = TryCast(MoveRowFromDataGridView(dtgHashtagDescripteurs, intSelectedRowIndex, "up"), Datatable)
End If
With dtgHashtagDescripteurs
.DataSource = Nothing
.Refresh()
.DataSource = tblUpdatedDataSource
.Refresh()
End With
End If
End Sub
Public Function MoveRowFromDataGridView(dgvToReorder As DataGridView, intSelectedRowIndex As Integer, strDirection As String) As DataTable
Dim tblSource As New DataTable
Dim rowToMove As DataRow
Dim rowCount As Integer
Dim rowsCollection As DataRowCollection
tblSource = TryCast(dgvToReorder.DataSource, DataTable)
If tblSource.Rows.Count > 0 Then
rowCount = tblSource.Rows.Count
rowsCollection = tblSource.Rows
If strDirection = "up" Then
rowToMove = rowsCollection(intSelectedRowIndex)
rowsCollection.Remove(rowToMove)
rowsCollection.InsertAt(rowToMove, intSelectedRowIndex - 1)
ElseIf strDirection = "down" Then
rowToMove = rowsCollection(intSelectedRowIndex)
rowsCollection.Remove(rowToMove)
rowsCollection.InsertAt(rowToMove, intSelectedRowIndex 1)
End If
End If
Return tblSource
End Function
Several questions:
In debugging mode, when the app runs in
MoveRowFromDataGridView
, tblSource got rows correctly sorted but got nothing once back MoveRowFromDataGridView.Updates to rowsCollection seems to pass on tblSource. Is there a way to prevent from that?
An other weird thing is the line
tblUpdatedDataSource = TryCast(MoveRowFromDataGridView(dtgHashtagDescripteurs, intSelectedRowIndex, "up"), Datatable)
If I code like this:tblUpdatedDataSource = MoveRowFromDataGridView(dtgHashtagDescripteurs, intSelectedRowIndex, "up")
I have an error "Option Strict On disallows implicit conversions from Datatable to Datatable"
CodePudding user response:
I finally found how to do this. I guess there would be more effective and elegant ways to do this, but this one works.
The user is allowed to move up/down row from the datagridview (called dtgHashtagDescripteurs) only if the text of button (in the same form where the datagridview is) is equal to "Ajouter" or "Modifier".
Private Sub dtgHashtagDescripteurs_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles dtgHashtagDescripteurs.KeyDown
Dim tblUpdatedDataSource As New System.Data.DataTable()
If Me.btnHashtagValidate.Text = "Valider" Or Me.btnHashtagValidate.Text = "Ajouter" Then
If e.KeyCode.Equals(Keys.Down) Or e.KeyCode.Equals(Keys.Up) Then
Dim intSelectedRowIndex As Integer = dtgHashtagDescripteurs.CurrentCell.RowIndex
If intSelectedRowIndex = dtgHashtagDescripteurs.Rows.Count Then
Exit Sub
Else
If e.KeyCode.Equals(Keys.Down) Then
tblUpdatedDataSource = TryCast(MoveRowFromDataGridView(dtgHashtagDescripteurs, intSelectedRowIndex, "down"), System.Data.DataTable)
ElseIf e.KeyCode.Equals(Keys.Up) Then
tblUpdatedDataSource = TryCast(MoveRowFromDataGridView(dtgHashtagDescripteurs, intSelectedRowIndex, "up"), System.Data.DataTable)
End If
With dtgHashtagDescripteurs
.AutoGenerateColumns = False
.DataSource = Nothing
.Columns.Clear()
.Refresh()
.DataSource = tblUpdatedDataSource
.AutoGenerateColumns = True
.Columns(0).HeaderText = "Libellé"
.Columns(0).Name = "libelle"
.Columns(0).Width = CInt(.Width / 3)
.Columns(1).HeaderText = "Précision Indexation"
.Columns(1).Name = "precision_indexation"
.Columns(1).Width = CInt(.Width / 3)
.Columns(2).HeaderText = "Reference"
.Columns(2).Name = "reference"
.Columns(2).Width = CInt(.Width / 3)
.ReadOnly = False
.Refresh()
End With
For i = dtgHashtagDescripteurs.Columns.Count - 1 To 0 Step -1
If i = 1 Then
dtgHashtagDescripteurs.Columns(i).ReadOnly = False
Else
dtgHashtagDescripteurs.Columns(i).ReadOnly = True
End If
Next
End If
End If
End If
e.Handled = True
End Sub
Public Function MoveRowFromDataGridView(dgvToReorder As DataGridView, intSelectedRowIndex As Integer, strDirection As String) As System.Data.DataTable
Dim newIndex As Integer
Dim tblToReorder As New DataTable
Dim colDescripteursLibelle As New DataColumn("libelle", GetType(String))
Dim colDescripteursReference As New DataColumn("precision_indexation", GetType(String))
Dim colDescripteursPrecision As New DataColumn("reference", GetType(String))
Dim lstDescripteursToReorder As List(Of Descripteur) = New List(Of Descripteur)()
tblToReorder.Columns.Add(colDescripteursLibelle)
tblToReorder.Columns.Add(colDescripteursReference)
tblToReorder.Columns.Add(colDescripteursPrecision)
If strDirection = "up" Then
newIndex = intSelectedRowIndex - 1
ElseIf strDirection = "down" Then
newIndex = intSelectedRowIndex 1
End If
If dgvToReorder.DataSource IsNot Nothing Then
tblToReorder = CType(dgvToReorder.DataSource, DataTable)
tblToReorder.Columns(0).ColumnName = "libelle"
tblToReorder.Columns(1).ColumnName = "precision_indexation"
tblToReorder.Columns(2).ColumnName = "reference"
Else
tblToReorder = GetDataTableFromDataGridView(dgvToReorder)
End If
If strDirection = "up" And intSelectedRowIndex = 0 Then
Return tblToReorder
End If
If strDirection = "down" And intSelectedRowIndex = dgvToReorder.Rows.Count - 1 Then
Return tblToReorder
End If
For i As Integer = 0 To tblToReorder.Rows.Count - 1
Dim descripteurToCopy As New Descripteur
If tblToReorder.Rows(i)("precision_indexation").ToString Is Nothing Then
descripteurToCopy.strPrecisionIndexation = Nothing
Else
descripteurToCopy.strPrecisionIndexation = CStr(tblToReorder.Rows(i)("precision_indexation").ToString)
End If
descripteurToCopy.intReference = CInt(tblToReorder.Rows(i)("reference"))
descripteurToCopy.strLibelle = CStr(tblToReorder.Rows(i)("libelle"))
lstDescripteursToReorder.Add(descripteurToCopy)
Next
Dim descripteurToMove As Descripteur = lstDescripteursToReorder(intSelectedRowIndex)
Dim descripteurInTarget As Descripteur = lstDescripteursToReorder(newIndex)
lstDescripteursToReorder.Remove(descripteurToMove)
lstDescripteursToReorder.Insert(newIndex, descripteurToMove)
lstDescripteursToReorder.Remove(descripteurInTarget)
lstDescripteursToReorder.Insert(intSelectedRowIndex, descripteurInTarget)
Return ListToDataTable(lstDescripteursToReorder)
End Function
Public Function ListToDataTable(Of T)(ByVal items As List(Of T)) As DataTable
Dim dataTable As DataTable = New DataTable(GetType(T).Name)
Dim Props As PropertyInfo() = GetType(T).GetProperties(BindingFlags.[Public] Or BindingFlags.Instance)
For Each prop As PropertyInfo In Props
Dim type = (If(prop.PropertyType.IsGenericType AndAlso prop.PropertyType.GetGenericTypeDefinition() = GetType(Nullable(Of)), Nullable.GetUnderlyingType(prop.PropertyType), prop.PropertyType))
dataTable.Columns.Add(prop.Name, type)
Next
For Each item As T In items
Dim values = New Object(Props.Length - 1) {}
For i As Integer = 0 To Props.Length - 1
values(i) = Props(i).GetValue(item, Nothing)
Next
dataTable.Rows.Add(values)
Next
Return dataTable
End Function