Manter posição da DataGridView após ordenação
A DataGridView
permite ordenar os seus dados de uma forma automática, bastando para isso clicar nos cabeçalhos das colunas. É sem dúvida muito prático e sem recorrer a qualquer código (por parte do utilizador). O que não é prático é que a lista perde a selecção após ordenação, ou seja, após a lista ser ordenada pela coluna X, a selecção actual perde-se.
Para resolver este problema pode-se criar uma walkaround onde é guardado um identificador único da lista (no exemplo um ID) e o index da coluna. Desta forma é possível ordenar a lista e manter a selecção actual.
Exemplo
' Variável que irá guardar a informação do ID seleccionado
Private currentRowID As Integer
' Variável que irá guardar a informação da coluna seleccionada
Private currentCellIndex As Integer
''' <summary>
''' Pesquisa na lista pelo ID e retorna o index da linha encontrada
''' </summary>
''' <param name="ID">Número único da lista (ID)</param>
Function getDGindex(ByVal ID As Integer) As Integer
Dim dr As DataGridViewRow
For Each dr In DataGridView1.Rows
If CType(dr.Cells(0).Value, Integer) = ID Then
Return dr.Index
End If
Next
End Function
' No arranque do form carrega alguns dados para o exemplo
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Criação de uma nova datatable que
' irá servir para preencher a DataGridView
Dim dt As New DataTable
' Criação de algumas colunas
dt.Columns.Add("ID", GetType(Byte))
dt.Columns.Add("Description", GetType(String))
dt.Columns.Add("Random", GetType(Integer))
' Criação de um número aleatório
Dim rnd As New Random
Dim dr As DataRow
' Insere registos na datatable
For x As Byte = 0 To 100
dr = dt.NewRow
dr("ID") = x
dr("Description") = "Item " & x.ToString.PadLeft(3, "0"c)
dr("Random") = rnd.Next(0, 1000)
dt.Rows.Add(dr)
Next
' Associa a DataTable à source da DataGridView
Me.DataGridView1.DataSource = dt
End Sub
' No evento RowLeave guarda o ID e indice da coluna
Private Sub DataGridView1_RowLeave(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.RowLeave
If e.RowIndex <> -1 And Not Me.DataGridView1.Rows(e.RowIndex).IsNewRow Then
currentRowID = CType(Me.DataGridView1(0, e.RowIndex).Value, Integer)
currentCellIndex = e.ColumnIndex
End If
End Sub
' Após a ordenação verifica a posição anterior e selecciona-a
Private Sub DataGridView1_Sorted(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGridView1.Sorted
Dim index As Integer = getDGindex(currentRowID)
Me.DataGridView1.CurrentCell = Me.DataGridView1.Rows(index).Cells(currentCellIndex)
End Sub