ListView Column Sort Demo

Reverend Jim 0 Tallied Votes 2K Views Share

This is a short bit of code that shows how to implement sorting on columns in a details-mode ListView. Suggestions for improvement are always welcome. One possible improvement would be to modify the column headers to indicate which column is being sorted and in which direction.

'                                                                                   
'  Name:                                                                            
'                                                                                   
'    ListViewSortDemo                                                               
'                                                                                   
'  Description:                                                                     
'                                                                                   
'    Demo code to show how to sort by clicking on a ListView column.                
'                                                                                   
'  Notes:                                                                           
'                                                                                   
'    To create the form for this project you only have to add a ListView control    
'    to a blank form. Put the listview into details mode and add four columns.      
'    Set the widths of all columns to 100. Set the font to Courier New (or some     
'    other monospaced font). All listview entries for this demo are added at run    
'    time.                                                                          
'                                                                                   
'    I keep track of the current sort order by using the Tag property of each       
'    column. I use +1 and -1 because it is so easy to toggle.                       
'                                                                                   
'    In order to sort you must create a custom class that implements the IComparer  
'    interface. It will have one method named Compare which will return one of      
'    three values indicating the result of the comparison. If you are sorting from  
'    smallest to largest then the values returned are:                              
'                                                                                   
'      -1  -  item1 < item2                                                         
'       0  -  item1 = item2                                                         
'      +1  -  item1 > item2                                                         
'                                                                                   
'    If you are sorting from largest to smallest then reverse the signs.            
'                                                                                   
'    The Compare function need not be restricted to one column or be based on a     
'    strict numerical or string comparison. This demo uses three custom compare     
'    classes.                                                                       
'                                                                                   
'    NumericSorter                                                                  
'                                                                                   
'      Sorts all rows based on the integer values in column 1                       
'                                                                                   
'    SumSorter                                                                      
'                                                                                   
'      Sorts all rows based on the sums of the digits in column 2                   
'                                                                                   
'    NameSorter                                                                     
'                                                                                   
'      Does a two column sort. It sorts all rows based on the string value in       
'      column 3, then the string value in column 4.                                 
'                                                                                   
'  Audit:                                                                           
'                                                                                   
'    2012-08-12  Reverend Jim original code                                         
'                                                                                   

Public Class Form1

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

        'Keep track of the last selected sort order using the Tag property

        For Each col As Object In ListView1.Columns
            col.tag = -1
        Next

        'populate a four column listview with some data

        AddRow(ListView1, {"87013", "87013", "Fred", "Stalder"})
        AddRow(ListView1, {"90215", "90215", "Virgil", "Samms"})
        AddRow(ListView1, {"600021", "600021", "Rod", "Kinnison"})
        AddRow(ListView1, {"2457", "2457", "Fred", "Flintstone"})
        AddRow(ListView1, {"7259", "7259", "Nils", "Bergenholm"})

    End Sub

    Private Sub AddRow(lvw As ListView, data() As String)

        'add a row to the given listview

        Dim item As New ListViewItem()
        item.Text = data(0)

        For i As Integer = 1 To UBound(data)
            item.SubItems.Add(data(i))
        Next

        lvw.Items.Add(item)

    End Sub

    Private Sub ListView1_ColumnClick(sender As System.Object, e As System.Windows.Forms.ColumnClickEventArgs) Handles ListView1.ColumnClick

        Dim lvw As ListView = sender

        'sort on the clicked column

        Select Case e.Column
            Case 0 : lvw.ListViewItemSorter = New NumericSorter
            Case 1 : lvw.ListViewItemSorter = New SumSorter
            Case 2 : lvw.ListViewItemSorter = New NameSorter(2, 3)
            Case 3 : lvw.ListViewItemSorter = New NameSorter(3, 2)
        End Select

        'Toggle sort order

        lvw.Sorting = IIf(lvw.Columns(e.Column).Tag = -1, SortOrder.Ascending, SortOrder.Descending)
        lvw.Columns(e.Column).Tag *= -1

    End Sub

    Class NumericSorter      'sorts on the first column based on the numeric value

        Implements IComparer

        Public Function Compare(x As Object, y As Object) As Integer Implements System.Collections.IComparer.Compare

            Dim item1 As ListViewItem = x
            Dim item2 As ListViewItem = y

            If item1.ListView.Sorting = SortOrder.Ascending Then
                Return Math.Sign(CInt(item1.SubItems(0).Text) - CInt(item2.SubItems(0).Text))
            Else
                Return -Math.Sign(CInt(item1.SubItems(0).Text) - CInt(item2.SubItems(0).Text))
            End If

        End Function

    End Class

    Class SumSorter          'sorts on the second column based on the sum of the digits

        Implements IComparer

        Public Function Compare(x As Object, y As Object) As Integer Implements System.Collections.IComparer.Compare

            Dim item1 As ListViewItem = x
            Dim item2 As ListViewItem = y

            Dim sum1 As Integer = 0
            Dim sum2 As Integer = 0

            For Each ch As Char In item1.SubItems(1).Text.ToCharArray
                sum1 += Val(ch)
            Next

            For Each ch As Char In item2.SubItems(1).Text.ToCharArray
                sum2 += Val(ch)
            Next

            If item1.ListView.Sorting = SortOrder.Ascending Then
                Return Math.Sign(sum1 - sum2)
            Else
                Return -Math.Sign(sum1 - sum2)
            End If

        End Function

    End Class

    Class NameSorter         'sorts on the two columns given in the constructor

        Implements IComparer

        Private _columns() As Integer

        Public Sub New(column1 As Integer, column2 As Integer)
            _columns = {column1, column2}
        End Sub

        Public Function Compare(x As Object, y As Object) As Integer Implements System.Collections.IComparer.Compare

            Dim item1 As ListViewItem = x
            Dim item2 As ListViewItem = y

            Dim text1 As String = item1.SubItems(_columns(0)).Text & item1.SubItems(_columns(1)).Text
            Dim text2 As String = item2.SubItems(_columns(0)).Text & item2.SubItems(_columns(1)).Text

            If item1.ListView.Sorting = SortOrder.Ascending Then
                Return StrComp(text1, text2)
            Else
                Return -StrComp(text1, text2)
            End If

        End Function

    End Class

End Class