Answered by:
Trouble Sorting ListView

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
- Proposed as answer by YiChun Chen Monday, June 15, 2009 9:32 AM
- Marked as answer by Martin Xie - MSFT Wednesday, June 17, 2009 6:51 AM
Thursday, June 11, 2009 3:24 AM
All replies
-
Thursday, June 11, 2009 2:50 AM
-
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
- Proposed as answer by YiChun Chen Monday, June 15, 2009 9:32 AM
- Marked as answer by Martin Xie - MSFT Wednesday, June 17, 2009 6:51 AM
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 ClassGreg
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