Ir para o conteúdo

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