Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter
 
 
 
MSDN Visual Basic Community
 
 
 
 
 
TitleMake a ListView control sort using the column you click in VB .NET
Description
KeywordsListView, sort, clicked column, VB.NET
CategoriesVB.NET, Controls
 
You can make the ListView sort by setting its Sorting property to Ascending or Descending. However, the control only sorts on its items not their sub-items. It won't even use the sub-items to brak ties when the items have the same text.

To modify the control's sorting behavior, you must create a class that implements the IComparer interface. The key to this class is the Compare function. This function takes as parameters two ListView items to compare. It should return -1 if the first should come before the second in the sort order, 0 if the items are equal, and 1 if the first should come after the second.

The ListViewComparer class has two private variables. The m_ColumnNumber variable that gives the column that the object will use for sorting. Variable m_SortOrder determines whether the control sorts ascending or descending. These values are set by the class's constructor.

The Compare function compares the appropriate sub-items in the two ListView items to determine how the two items should be ordered. It needs to do a little checking to guard against the case when either of the items doesn't have the sub-item that the object is trying to compare.

Thanks to Kevin G for the improved comparison code that tests numeric values as numbers rather than strings. (For example, as strings "9" comes after "100" but as numbers 9 comes before 100.)

Thanks to Joe Mestrovich for adding support for date columns. (For example, as strings "10/10/2000" comes before "1/1/1999" but as dates 10/10/2000 comes after 1/1/1999. Also as strings "01/20/2009" comes before "1/1/2009" but as dates 01/20/2009 comes after 1/1/2009.)

 
' Implements a comparer for ListView columns.
Class ListViewComparer
    Implements IComparer

    Private m_ColumnNumber As Integer
    Private m_SortOrder As SortOrder

    Public Sub New(ByVal column_number As Integer, ByVal _
        sort_order As SortOrder)
        m_ColumnNumber = column_number
        m_SortOrder = sort_order
    End Sub

    ' Compare the items in the appropriate column
    ' for objects x and y.
    Public Function Compare(ByVal x As Object, ByVal y As _
        Object) As Integer Implements _
        System.Collections.IComparer.Compare
        Dim item_x As ListViewItem = DirectCast(x, _
            ListViewItem)
        Dim item_y As ListViewItem = DirectCast(y, _
            ListViewItem)

        ' Get the sub-item values.
        Dim string_x As String
        If item_x.SubItems.Count <= m_ColumnNumber Then
            string_x = ""
        Else
            string_x = item_x.SubItems(m_ColumnNumber).Text
        End If

        Dim string_y As String
        If item_y.SubItems.Count <= m_ColumnNumber Then
            string_y = ""
        Else
            string_y = item_y.SubItems(m_ColumnNumber).Text
        End If

        ' Compare them.
        If m_SortOrder = SortOrder.Ascending Then
            If IsNumeric(string_x) And IsNumeric(string_y) _
                Then
                Return Val(string_x).CompareTo(Val(string_y))
            ElseIf IsDate(string_x) And IsDate(string_y) _
                Then
                Return DateTime.Parse(string_x).CompareTo(DateTime.Parse(string_y))
            Else
                Return String.Compare(string_x, string_y)
            End If
        Else
            If IsNumeric(string_x) And IsNumeric(string_y) _
                Then
                Return Val(string_y).CompareTo(Val(string_x))
            ElseIf IsDate(string_x) And IsDate(string_y) _
                Then
                Return DateTime.Parse(string_y).CompareTo(DateTime.Parse(string_x))
            Else
                Return String.Compare(string_y, string_x)
            End If
        End If
    End Function
End Class
 
The example program uses the following code to sort its ListView control data. Variable m_SortingColumn keeps track of the column that the program is currently sorting.

When the user clicks a column header, the program figures out which column was clicked. It then determines the new sorting order it should use. If the new column is the same as the old one, the program switches the sort order. Otherwise it sorts ascending.

The program adds "> " to the column header when it sorts ascending and it adds "< " when it sorts descending. It uses these characters to determine the current sort order.

After it decides on the new sort order, the program removes the sorting indicator ("> " or "< ") from the current sort column and adds it to the new sort column.

Finally, the program creates a new ListViewItemSorter object, passing its constructor the appropriate column number and sort order. It then calls the ListView control's Sort method to make it resort its data.

 
' The column currently used for sorting.
Private m_SortingColumn As ColumnHeader

' Sort using the clicked column.
Private Sub lvwBooks_ColumnClick(ByVal sender As _
    System.Object, ByVal e As _
    System.Windows.Forms.ColumnClickEventArgs) Handles _
    lvwBooks.ColumnClick
    ' Get the new sorting column.
    Dim new_sorting_column As ColumnHeader = _
        lvwBooks.Columns(e.Column)

    ' Figure out the new sorting order.
    Dim sort_order As System.Windows.Forms.SortOrder
    If m_SortingColumn Is Nothing Then
        ' New column. Sort ascending.
        sort_order = SortOrder.Ascending
    Else
        ' See if this is the same column.
        If new_sorting_column.Equals(m_SortingColumn) Then
            ' Same column. Switch the sort order.
            If m_SortingColumn.Text.StartsWith("> ") Then
                sort_order = SortOrder.Descending
            Else
                sort_order = SortOrder.Ascending
            End If
        Else
            ' New column. Sort ascending.
            sort_order = SortOrder.Ascending
        End If

        ' Remove the old sort indicator.
        m_SortingColumn.Text = _
            m_SortingColumn.Text.Substring(2)
    End If

    ' Display the new sort order.
    m_SortingColumn = new_sorting_column
    If sort_order = SortOrder.Ascending Then
        m_SortingColumn.Text = "> " & m_SortingColumn.Text
    Else
        m_SortingColumn.Text = "< " & m_SortingColumn.Text
    End If

    ' Create a comparer.
    lvwBooks.ListViewItemSorter = New _
        ListViewComparer(e.Column, sort_order)

    ' Sort.
    lvwBooks.Sort()
End Sub
 
 
Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated