locked
Trouble Sorting ListView RRS feed

  • Question

  • All,

    I have a ListView w/filename, data, time and size fields. I've copied the code from this article http://msdn.microsoft.com/en-us/library/ms996467.aspx to use in my solution. Problem is, when I click a column header the first time, it sorts, but when I click the same header a second time, to sort in reverse, the column stays in the same order as it was just sorted in. Any suggestions? Thanks in advance.
    Thursday, June 11, 2009 2:37 AM

Answers

  • The article you link to starts out with code that only sorts in one direction and then shows how to update the code to be able to switch directions.  Did you implement the second version of the code?  If so can you post your code for the ListView.ColumnClick event and the ListViewItemComparer class? 

    Here is the code from the article:

    Private Sub listView1_ColumnClick(sender As Object, e As
                    System.Windows.Forms.ColumnClickEventArgs)
        ' Determine whether the column is the same as the last column clicked.
        If e.Column <> sortColumn Then
            ' Set the sort column to the new column.
            sortColumn = e.Column
            ' Set the sort order to ascending by default.
            listView1.Sorting = SortOrder.Ascending
        Else
            ' Determine what the last sort order was and change it.
            If listView1.Sorting = SortOrder.Ascending Then
                listView1.Sorting = SortOrder.Descending
            Else
                listView1.Sorting = SortOrder.Ascending
            End If
        End If 
        ' Call the sort method to manually sort.
        listView1.Sort()
        ' Set the ListViewItemSorter property to a new ListViewItemComparer
        ' object.
        listView1.ListViewItemSorter = New ListViewItemComparer(e.Column, _
                                                         listView1.Sorting)
    End Sub
    
    Class ListViewItemComparer
        Implements IComparer 
        Private col As Integer
        Private order as SortOrder
        
        Public Sub New()
            col = 0
            order = SortOrder.Ascending
        End Sub
        
        Public Sub New(column As Integer, order as SortOrder)
            col = column
            Me.order = order
        End Sub
        
        Public Function Compare(x As Object, y As Object) As Integer _
                            Implements System.Collections.IComparer.Compare
            Dim returnVal as Integer = -1
            returnVal = [String].Compare(CType(x, _
                            ListViewItem).SubItems(col).Text, _
                            CType(y, ListViewItem).SubItems(col).Text)
            ' Determine whether the sort order is descending.
            If order = SortOrder.Descending Then
                ' Invert the value returned by String.Compare.
                returnVal *= -1
            End If
    
            Return returnVal
        End Function
    End Class
    



    Thursday, June 11, 2009 3:24 AM

All replies

  • The article you link to starts out with code that only sorts in one direction and then shows how to update the code to be able to switch directions.  Did you implement the second version of the code?  If so can you post your code for the ListView.ColumnClick event and the ListViewItemComparer class? 

    Here is the code from the article:

    Private Sub listView1_ColumnClick(sender As Object, e As
                    System.Windows.Forms.ColumnClickEventArgs)
        ' Determine whether the column is the same as the last column clicked.
        If e.Column <> sortColumn Then
            ' Set the sort column to the new column.
            sortColumn = e.Column
            ' Set the sort order to ascending by default.
            listView1.Sorting = SortOrder.Ascending
        Else
            ' Determine what the last sort order was and change it.
            If listView1.Sorting = SortOrder.Ascending Then
                listView1.Sorting = SortOrder.Descending
            Else
                listView1.Sorting = SortOrder.Ascending
            End If
        End If 
        ' Call the sort method to manually sort.
        listView1.Sort()
        ' Set the ListViewItemSorter property to a new ListViewItemComparer
        ' object.
        listView1.ListViewItemSorter = New ListViewItemComparer(e.Column, _
                                                         listView1.Sorting)
    End Sub
    
    Class ListViewItemComparer
        Implements IComparer 
        Private col As Integer
        Private order as SortOrder
        
        Public Sub New()
            col = 0
            order = SortOrder.Ascending
        End Sub
        
        Public Sub New(column As Integer, order as SortOrder)
            col = column
            Me.order = order
        End Sub
        
        Public Function Compare(x As Object, y As Object) As Integer _
                            Implements System.Collections.IComparer.Compare
            Dim returnVal as Integer = -1
            returnVal = [String].Compare(CType(x, _
                            ListViewItem).SubItems(col).Text, _
                            CType(y, ListViewItem).SubItems(col).Text)
            ' Determine whether the sort order is descending.
            If order = SortOrder.Descending Then
                ' Invert the value returned by String.Compare.
                returnVal *= -1
            End If
    
            Return returnVal
        End Function
    End Class
    



    Thursday, June 11, 2009 3:24 AM
  • Blackwood,

    Here's my slightly modified code- I'm pretty sure I only changed names to suit my tastes. When I get into the office tomorrow, I'll double-check my code against that of the article and I'll also try bibliophage's link.

    Private Sub FileList_ColumnClick(ByVal sender As Object, ByVal e As System.Windows.Forms.ColumnClickEventArgs) Handles FileList.ColumnClick
       Me.FileList_ColumnClick
       With FileList
          If e.Column <> SortColumn Then
             SortColumn = e.Column
             .Sorting = SortOrder.Ascending
          Else
             If .Sorting = SortOrder.Ascending Then
                .Sorting = SortOrder.Descending
             ElseIf .Sorting = SortOrder.Descending Then
                .Sorting = SortOrder.Ascending
             End If
          End If


    .ListViewItemSorter = New ListViewItemComparer(e.Column, .Sorting) .Sort() End With 'FileList End Sub 'FileList_ColumnClick Class ListViewItemComparer Implements IComparer Private m_ColumnNumber As Integer Private m_SortOrder As SortOrder Public Sub New() m_ColumnNumber = 0 m_SortOrder = SortOrder.Ascending End Sub 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 = String.Empty Else string_x = item_x.SubItems(m_ColumnNumber).Text.Trim() End If Dim string_y As String = String.Empty If item_y.SubItems.Count <= m_ColumnNumber Then string_y = String.Empty Else string_y = item_y.SubItems(m_ColumnNumber).Text.Trim() 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 DateTime.Parse(string_x).CompareTo(DateTime.Parse(string_y)) 'End If Else Return String.Compare(string_x, string_y, True) 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 DateTime.Parse(string_y).CompareTo(DateTime.Parse(string_x)) 'End If Else Return String.Compare(string_y, string_x, True) End If End If End Function End Class

    Greg

    Thursday, June 11, 2009 3:39 AM
  • Code looks fine. Did you step through the code to see if the conditions are executing as expected.
    If this post is useful, mark it as answer.
    Thursday, June 11, 2009 8:33 AM