Classificar listview ao clicar na coluna - VB.NET

Ao trabalhar com ListViews, é comum querer ordenar seu conteúdo com base em uma coluna. Um exemplo ocorre no Windows Explorer: quando você clica em um dos cabeçalhos de coluna, a lista é reorganizada em ordem crescente/decrescente.

Minha intenção aqui é mostrar uma maneira de organizar, em ordem alfabética, os textos, números ou datas dos itens de uma ListView, tanto ao se clicar no título de uma de suas colunas como também ao terminar de preenchê-la, para uma aplicação desenvolvida utilizando o Visual Basic .NET como linguagem.

Para ordená-la de acordo com a primeira coluna, logo após preenchê-la, inclua uma das seguintes linhas após o código que preenche sua ListView:

'ordenar A-Z
NomeDaSuaListview.Sorting = SortOrder.Ascending

'ordenar Z-A
NomeDaSuaListview.Sorting = SortOrder.Descending

'desativar
NomeDaSuaListview.Sorting = SortOrder.None

E pronto, problema resolvido. Talvez seja necessário desativar esta propriedade quando for preencher novamente essa ListView.

Mas, se você deseja ordenar clicando nos títulos das colunas, a primeira coisa a se fazer é adicionar uma nova classe ao seu projeto. Para isto, clique no menu Project e em Add Class... - isto no Visual Studio 2015 em inglês, pode variar um pouco nas demais versões. Digite o nome clsOrganizarColunasLvw.cls para a classe e clique em Add.

Apague tudo o que estiver escrito dentro da classe criada e adicione o seguinte código:

Public Class clsOrganizarColunasLvw
    Implements IComparer
    Private mSortColumn As Integer
    Private mSortOrder As SortOrder

    Public Enum SortOrder
        Ascending
        Descending
    End Enum

    Public Sub New(ByVal sortColumn As Integer, ByVal sortOrder As SortOrder)
        mSortColumn = sortColumn
        mSortOrder = sortOrder
    End Sub

    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
        Dim Result As Integer
        Dim ItemX As ListViewItem
        Dim ItemY As ListViewItem
        ItemX = CType(x, ListViewItem)
        ItemY = CType(y, ListViewItem)
        If mSortColumn = 0 Then
            Result = DateTime.Compare(CType(ItemX.Text, DateTime), CType(ItemY.Text, DateTime))
        Else
            Result = DateTime.Compare(CType(ItemX.SubItems(mSortColumn).Text, DateTime), CType(ItemY.SubItems(mSortColumn).Text, DateTime))
        End If
        If mSortOrder = SortOrder.Descending Then
            Result = -Result
        End If
        Return Result
    End Function
End Class

Public Class ListViewStringSort
    Implements IComparer
    Private mSortColumn As Integer
    Private mSortOrder As SortOrder

    Public Sub New(ByVal sortColumn As Integer, ByVal sortOrder As SortOrder)
        mSortColumn = sortColumn
        mSortOrder = sortOrder
    End Sub

    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
        Dim Result As Integer
        Dim ItemX As ListViewItem
        Dim ItemY As ListViewItem
        ItemX = CType(x, ListViewItem)
        ItemY = CType(y, ListViewItem)
        If mSortColumn = 0 Then
            Result = ItemX.Text.CompareTo(ItemY.Text)
        Else
            Result = ItemX.SubItems(mSortColumn).Text.CompareTo(ItemY.SubItems(mSortColumn).Text)
        End If
        If mSortOrder = SortOrder.Descending Then
            Result = -Result
        End If
        Return Result
    End Function
End Class

Public Class ListViewNumericSort
    Implements IComparer
    Private mSortColumn As Integer
    Private mSortOrder As SortOrder

    Public Sub New(ByVal sortColumn As Integer, ByVal sortOrder As SortOrder)
        mSortColumn = sortColumn
        mSortOrder = sortOrder
    End Sub

    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
        Dim Result As Integer
        Dim ItemX As ListViewItem
        Dim ItemY As ListViewItem
        ItemX = CType(x, ListViewItem)
        ItemY = CType(y, ListViewItem)
        If mSortColumn = 0 Then
            Result = Decimal.Compare(CType(ItemX.Text, Decimal), CType(ItemY.Text, Decimal))
        Else
            Result = Decimal.Compare(CType(ItemX.SubItems(mSortColumn).Text, Decimal), CType(ItemY.SubItems(mSortColumn).Text, Decimal))
        End If
        If mSortOrder = SortOrder.Descending Then
            Result = -Result
        End If
        Return Result
    End Function
End Class

Public Class ListViewDateSort
    Implements IComparer
    Private mSortColumn As Integer
    Private mSortOrder As SortOrder

    Public Sub New(ByVal sortColumn As Integer, ByVal sortOrder As SortOrder)
        mSortColumn = sortColumn
        mSortOrder = sortOrder
    End Sub

    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
        Dim Result As Integer
        Dim ItemX As ListViewItem
        Dim ItemY As ListViewItem
        ItemX = CType(x, ListViewItem)
        ItemY = CType(y, ListViewItem)
        If mSortColumn = 0 Then
            Result = DateTime.Compare(CType(ItemX.Text, DateTime), CType(ItemY.Text, DateTime))
        Else
            Result = DateTime.Compare(CType(ItemX.SubItems(mSortColumn).Text, DateTime), CType(ItemY.SubItems(mSortColumn).Text, DateTime))
        End If
        If mSortOrder = SortOrder.Descending Then
            Result = -Result
        End If
        Return Result
    End Function
End Class

O código acima já inclui a ordenação para strings, números e datas. Agora dê um duplo-clique no formulário onde está localizada sua ListView e adicione o seguinte código:

Public Sub SortMyListView(ByVal ListViewToSort As ListView, ByVal ColumnNumber As Integer, Optional ByVal Resort As Boolean = False, Optional ByVal ForceSort As Boolean = False)
        Dim SortOrder As SortOrder
        Static LastSortColumn As Integer = -1
        Static LastSortOrder As SortOrder = SortOrder.Ascending
        If Resort = True Then
            SortOrder = LastSortOrder
        ElseIf LastSortColumn = ColumnNumber Then
            If LastSortOrder = SortOrder.Ascending Then
                SortOrder = SortOrder.Descending
            Else
                SortOrder = SortOrder.Ascending
            End If
        Else
            SortOrder = SortOrder.Ascending
        End If
        If String.IsNullOrEmpty(CStr(ListViewToSort.Columns(ColumnNumber).Tag)) Then
            If ForceSort = True Then
                ListViewToSort.Columns(ColumnNumber).Tag = "String"
            Else
                Exit Sub
            End If
        End If
        Select Case ListViewToSort.Columns(ColumnNumber).Tag.ToString
            Case "Numeric"
                ListViewToSort.ListViewItemSorter = New ListViewNumericSort(ColumnNumber, SortOrder)
            Case "Date"
                ListViewToSort.ListViewItemSorter = New ListViewDateSort(ColumnNumber, SortOrder)
            Case "String"
                ListViewToSort.ListViewItemSorter = New ListViewStringSort(ColumnNumber, SortOrder)
        End Select
        LastSortColumn = ColumnNumber
        LastSortOrder = SortOrder
        ListViewToSort.ListViewItemSorter = Nothing
    End Sub

Pronto, a parte mais complicada está terminada. Para finalizar você deverá adicionar um evento que será chamado quando o usuário clicar na coluna do seu ListView. Clique com o botão direito na sua ListView e vá em Properties. Na guia Events, dê um duplo-clique em ColumnClick e você será redirecionado para a edição de código. Apenas acrescente a seguinte linha:

Call SortMyListView(lvwConsulta, e.Column, , True)

Ou seja, ficará semelhante à isto:

Private Sub NomeDoSeuListView_ColumnClick(sender As Object, e As ColumnClickEventArgs) Handles NomeDoSeuListView.ColumnClick        
     Call SortMyListView(lvwConsulta, e.Column, , True)
End Sub

Pronto! Agora salve seu projeto, execute e clique em vários cabeçalhos do seu ListView para testar.

Postar um comentário