Sort by Columnheader click

jdy0803

Well-known member
Joined
Sep 9, 2012
Messages
73
Location
Santa Clarita
Programming Experience
10+
I want to make listview to be sorted by columnheader click.
I made code like this.
VB.NET:
[/COLOR][COLOR=#333333]Class ListViewItemComparer[/COLOR]
        Implements IComparer
        Private col As Integer
        Private AscOrder As Boolean

        Public Sub New()
            col = 0
            AscOrder = True
        End Sub
        Public Sub New(ByVal column As Integer, ByVal Ascending As Boolean)
            col = column
            AscOrder = Ascending
        End Sub

        Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
            If AscOrder Then
                Return [String].Compare(CType(x, ListViewItem).SubItems(col).Text, CType(y, ListViewItem).SubItems(col).Text)
            Else
                Return [String].Compare(CType(y, ListViewItem).SubItems(col).Text, CType(x, ListViewItem).SubItems(col).Text)
            End If
        End Function
    End Class


    Private Sub ListView1_ColumnClick(ByVal sender As Object, ByVal e As System.Windows.Forms.ColumnClickEventArgs) Handles ListView1.ColumnClick
        ' Set the ListViewItemSorter property to a new ListViewItemComparer
        ' object. Setting this property immediately sorts the 
        ' ListView using the ListViewItemComparer object.

        'Change this based on which direction you want
        Dim blnAscending As Boolean = True
        bSortToggle = Not bSortToggle
        Me.ListView1.ListViewItemSorter = New ListViewItemComparer(e.Column, blnAscending) [COLOR=#333333]    End Sub[/COLOR][COLOR=#333333]
This code works well in case of column item is String but not in case of Integer or Date.
How to change code to fit to following columns?

Column(0) : String
Column(1) : Integer
Column(2) : Date
 
Hi,

The reason why the sort routine is not working for Date and Integer columns in the ListView is because the information stored in the ListViewItems is of type Text and no other Type and therefore the sort routines are performing standard string comparisons on the dates and integers. To get round this, here is an expansion of your Sorting class to do this correctly:-

VB.NET:
Public Class LVISortOptions
  Public Class SortStrings
    Implements IComparer
    Private col As Integer
    Private AscOrder As Boolean
 
    Public Sub New()
      col = 0
      AscOrder = True
    End Sub
    Public Sub New(ByVal column As Integer, ByVal Ascending As Boolean)
      col = column
      AscOrder = Ascending
    End Sub
 
    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
      If AscOrder Then
        Return DirectCast(x, ListViewItem).SubItems(col).Text.CompareTo(DirectCast(y, ListViewItem).SubItems(col).Text)
      Else
        Return DirectCast(y, ListViewItem).SubItems(col).Text.CompareTo(DirectCast(x, ListViewItem).SubItems(col).Text)
      End If
    End Function
  End Class
 
  Public Class SortIntegers
    Implements IComparer
    Private col As Integer
    Private AscOrder As Boolean
 
    Public Sub New()
      col = 0
      AscOrder = True
    End Sub
    Public Sub New(ByVal column As Integer, ByVal Ascending As Boolean)
      col = column
      AscOrder = Ascending
    End Sub
 
    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
      If AscOrder Then
        Return CInt(DirectCast(x, ListViewItem).SubItems(col).Text).CompareTo(CInt(DirectCast(y, ListViewItem).SubItems(col).Text))
      Else
        Return CInt(DirectCast(y, ListViewItem).SubItems(col).Text).CompareTo(CInt(DirectCast(x, ListViewItem).SubItems(col).Text))
      End If
    End Function
  End Class
 
  Public Class SortDates
    Implements IComparer
    Private col As Integer
    Private AscOrder As Boolean
 
    Public Sub New()
      col = 0
      AscOrder = True
    End Sub
    Public Sub New(ByVal column As Integer, ByVal Ascending As Boolean)
      col = column
      AscOrder = Ascending
    End Sub
 
    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
      If AscOrder Then
        Return CDate(DirectCast(x, ListViewItem).SubItems(col).Text).CompareTo(CDate(DirectCast(y, ListViewItem).SubItems(col).Text))
      Else
        Return CDate(DirectCast(y, ListViewItem).SubItems(col).Text).CompareTo(CDate(DirectCast(x, ListViewItem).SubItems(col).Text))
      End If
    End Function
  End Class
End Class

This can then be used in the following manner when sorting your ListView columns:-

VB.NET:
ListView1.ListViewItemSorter = New LVISortOptions.SortStrings(0, True)
ListView1.ListViewItemSorter = New LVISortOptions.SortDates(1, True)
ListView1.ListViewItemSorter = New LVISortOptions.SortIntegers(2, True)
 
'etc

All that said, If you used a DataGridView instead of a ListView then the columns already provide default sort routines when the columns are clicked, (based on the correct type), without having to write your own.

Hope that helps.

Cheers,

Ian
 
Back
Top