VB2005 - Listview Column Sort
I'm having a problem that is cited fairly commonly on the net. I've tried various solutions and all of them have the same problem.
I'm trying to do a column sort. String variables sort nicely. However variables that are integer variables don't sort at all. The order is very messed up. There is some sorting but not based in the full magnitude of the sorted integers.
Can anyone help me with this. I've tried several ways of doing this, beginning with MSDN examples and they all have the same failing.
[510 byte] By [
ReneeC] at [2007-12-16]
can you post your code, because mine sort just fine in C#
I got it....
And a little while later, I'll be happy to post it !
This is my first managed code project and I must admit, I'm impressed with vb2005 in everything except performance.
sure why not post it for those who could find it useful
OK.... I got most of this off the net and have modified it. It's very stable and works really well.
This sort works on Numeric, Alphanumeric and Data formats.
You have to declare the datatype in column headers like so:
With
lvPrView
.View = View.Details
' Add a column with width 20 and left alignment
.Columns.Add(
"Process", 150, HorizontalAlignment.Center) .Columns(0).Tag =
"String" .Columns.Add(
"Pid", 45, HorizontalAlignment.Right) .Columns(1).Tag =
"Numeric" .Columns.Add(
"% CPU", 50, HorizontalAlignment.Center) .Columns(2).Tag =
"Numeric" .Columns.Add("File Name", 500, HorizontalAlignment.Left) .Columns(6).Tag =
"String" End WithThe sort code occurs in a routine and a separate class...
The routine associated with a column click....
Private Sub lvPrView_ColumnClick(ByVal sender As Object, ByVal e As System.Windows.Forms.ColumnClickEventArgs) Handles lvPrView.ColumnClick
'Sort when a Column Header is Clicked
Dim SortOrder As SortOrder Static LastSortColumn As Integer = -1 Static LastSortOrder As SortOrder = SortOrder.Ascending If LastSortColumn = e.Column Then If LastSortOrder = SortOrder.Ascending Then SortOrder = SortOrder.Descending
Else SortOrder = SortOrder.Ascending
End If Else SortOrder = SortOrder.Ascending
End If Select Case lvPrView.Columns(e.Column).Tag Case "Numeric" lvPrView.ListViewItemSorter =
New ListViewNumericSort(e.Column, SortOrder) Case "String" lvPrView.ListViewItemSorter =
New ListViewStringSort(e.Column, SortOrder) Case "Date" lvPrView.ListViewItemSorter =
New ListViewDateSort(e.Column, SortOrder) End Select LastSortColumn = e.Column
LastSortOrder = SortOrder
lvPrView.ListViewItemSorter =
Nothing End SubAnd then the class module.....
Imports
System.Collections
Imports
System.Windows.Forms Public
Enum SortOrder Ascending
Descending
End
Enum Public
Class ListViewDateSort Implements IComparer Private mSortColumn As Integer Private mSortOrder As SortOrder Public Sub New(ByVal sortColumn As Integer, ByVal sortOrder As SortOrder) mSortColumn = sortColumn
mSortOrder = sortOrder
End Sub Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare Dim Result As Integer Dim ItemX As ListViewItem Dim ItemY As ListViewItem ItemX =
CType(x, ListViewItem) ItemY =
CType(y, ListViewItem) If mSortColumn = 0 Then Result = DateTime.Compare(
CType(ItemX.Text, DateTime), CType(ItemY.Text, DateTime)) Else Result = DateTime.Compare(
CType(ItemX.SubItems(mSortColumn).Text, DateTime), CType(ItemY.SubItems(mSortColumn).Text, DateTime)) End If If mSortOrder = SortOrder.Descending Then Result = -Result
End If Return Result End Function End
Class Public
Class ListViewStringSort Implements IComparer Private mSortColumn As Integer Private mSortOrder As SortOrder Public Sub New(ByVal sortColumn As Integer, ByVal sortOrder As SortOrder) mSortColumn = sortColumn
mSortOrder = sortOrder
End Sub Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare Dim Result As Integer Dim ItemX As ListViewItem Dim ItemY As ListViewItem ItemX =
CType(x, ListViewItem) ItemY =
CType(y, ListViewItem) If mSortColumn = 0 Then Result = ItemX.Text.CompareTo(ItemY.Text)
Else Result = ItemX.SubItems(mSortColumn).Text.CompareTo(ItemY.SubItems(mSortColumn).Text)
End If If mSortOrder = SortOrder.Descending Then Result = -Result
End If Return Result End Function End
Class Public
Class ListViewNumericSort Implements IComparer Private mSortColumn As Integer Private mSortOrder As SortOrder
Public Sub New(ByVal sortColumn As Integer, ByVal sortOrder As SortOrder) mSortColumn = sortColumn
mSortOrder = sortOrder
End Sub Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare Dim Result As Integer Dim ItemX As ListViewItem Dim ItemY As ListViewItem ItemX =
CType(x, ListViewItem) ItemY =
CType(y, ListViewItem) If mSortColumn = 0 Then Result =
Decimal.Compare(CType(ItemX.Text, Decimal), CType(ItemY.Text, Decimal)) Else Result =
Decimal.Compare(CType(ItemX.SubItems(mSortColumn).Text, Decimal), CType(ItemY.SubItems(mSortColumn).Text, Decimal)) End If If mSortOrder = SortOrder.Descending Then Result = -Result
End If Return Result End Function End
ClassHi!
I found the following code block at:
http://msdn.microsoft.com/library/spa/default.asp?url=/library/SPA/cpref/html/frlrfSystemWindowsFormsListViewClassListViewItemSorterTopic.asp
Code:
' ColumnClick event handler.
Private Sub ColumnClick(ByVal o As Object, ByVal e As ColumnClickEventArgs)
' Set the ListViewItemSorter property to a new ListViewItemComparer
' object. Setting this property immediately sorts the
' ListView using the ListViewItemComparer object.
Me.listView1.ListViewItemSorter = New ListViewItemComparer(e.Column)
End Sub
But i can't load the ListViewItemComparer function bacause y cannot find it.
Do you have any idea?
*************************
19:15
Wait....
Here is the url of the ListViewItemComparer Class
http://msdn2.microsoft.com/library/yw988w73(en-us,vs.80).aspx
And thi is the code:
' Implements the manual sorting of items by columns.
Class ListViewItemComparer
Implements IComparer
Private col As Integer
Public Sub New()
col = 0
End Sub
Public Sub New(ByVal column As Integer)
col = column
End Sub
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer _
Implements IComparer.Compare
Return [String].Compare(CType(x, ListViewItem).SubItems(col).Text, CType(y, ListViewItem).SubItems(col).Text)
End Function
End Class
*****************
But i found an error.. when you add items to the listview control and the do a sort by clicking the column and then add items again, the app crashes?
This application is a personal project, one that I was using to learn VB.Net.
It's a complex application. It's a real time taskmanager that runs continuosly and it frequently adding and deleting items as my system runs programs.
I have never seen it crash and it's received a lot of use especially while I was developing it.
I just tried the scenario you suggested, sorting, starting notepad, sorting, stoping notepad and sorting. The apllication was quite stable and did not flinch.
I could not reproduce the problem in the app.
I don't know whether that's 'good' or 'bad'. :(
I do remember, of course, looking at the Microsoft methods you've broached. As I remember them they didn't work and they didn't sort integer data. They may well have crashed. That's why I looked on the net for an alternative solution. This one really seems to work well.
I applied the code to VS2003 (w/o using the tag), how come the ColumnClick event is being fired twice when I step through the code (therefore it negates the ascend/decend reversal).
I wish I knew a couple of things....
I'm wondering how it works without the tags? Are you only using one datatype?
The other thing I'd wonder was what is firing those events?
I'd take a look at what messages that part of the control is receiving with SPY. I've never seen the behavior you are describing. :(
Hello,
plz could you tell me how can i get the selected item in a listview (multiselect disabled)? i wanna use it on an other form (form2)...