|
-
Jul 5th, 2006, 03:56 AM
#1
Thread Starter
New Member
ListViewSorter Class - there must be a better way to do this?
Hello,
I need to add the functionality to my listview contols so that they can be sorted by clicking on the column headers. In one of my list views I may have a lot of items - like a couple of thousand maybe.
The problem I have is in my sorter class in the compare method. I want my LV to sort by the data type that it is, ie if it's a date I don't want to sort it like a string! I have the following code and it is very very slow when sorting strings, but reasonable (just!) when doing dates which I presume is due to all the parsing I am doing
Can you give me an idea on how to better write this code?
Also, is there a better sorting method than this? Obv, a bubble sort (which I presume it is) isn't going to be best when dealing with a lot of data.
Code:
Public Class ListViewSorter
Implements System.Collections.IComparer
Private _SortIndex As Integer
Private _SortOrder As SortOrder
Public Sub New(ByVal SortIndex As Integer, ByVal sortorder As SortOrder)
_SortIndex = SortIndex
_SortOrder = sortorder
End Sub
Public Function Compare_(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
'Cast them to LVI's
Dim lviX As ListViewItem = CType(x, ListViewItem)
Dim lviY As ListViewItem = CType(y, ListViewItem)
'Get the strings out of em that we need to compare
Dim strX As String = lviX.SubItems(_SortIndex).Text
Dim strY As String = lviY.SubItems(_SortIndex).Text
Try ' See if we have a date
Dim dteX As Date = DateTime.Parse(strX)
Dim dteY As Date = DateTime.Parse(strY)
If _SortOrder = SortOrder.Ascending Then
Return DateTime.Compare(dteX, dteY)
Else
Return DateTime.Compare(dteY, dteX)
End If
Catch
Try ' See if we have a numeric
Dim intX As Integer = Integer.Parse(strX)
Dim inty As Integer = Integer.Parse(strY)
If intX > inty Then
If _SortOrder = SortOrder.Ascending Then
Return 1
Else
Return -1
End If
ElseIf intX < inty Then
If _SortOrder = SortOrder.Ascending Then
Return -1
Else
Return 1
End If
Else
Return 0
End If
Catch 'Just sort as a string
If _SortOrder = SortOrder.Ascending Then
Return String.Compare(strX, strY)
Else
Return String.Compare(strY, strX)
End If
End Try
End Try
End Function
End Class
-
Jul 5th, 2006, 04:06 AM
#2
Re: ListViewSorter Class - there must be a better way to do this?
Are you using VB 2005? Please specify your version in future.
It's all the exceptions being thrown that will be slowing things down the most. If you have a column of strings then you're throwing thousands of exceptions. That's absolutely terrible. You should know what type your columns are and then in the Compare method just check the column index and then use the data type for that column. Given that ListViews only contain strings you'd still need to parse the values if they were to be numbers or dates. You can still avoid some or all exceptions though. If you're using VB 2005 you should be using Integer.TryParse and Date.TryParse to attempt to parse the values. If they fail the method retruns False instead of throwing an exception, which is much more efficient. If you're using an earlier version then you should be using Double.TryParse to attempt to parse your numbers but unfortunately your stuck with catching exceptions for the dates.
-
Jul 5th, 2006, 04:25 AM
#3
Re: ListViewSorter Class - there must be a better way to do this?
E.g.
VB Code:
Private Enum ListViewColumnDataType
[String]
[Integer]
[Date]
End Enum
Private Class ListViewItemComparer
Implements IComparer
Private columnIndex As Integer
Private dataType As ListViewColumnDataType
Public Sub New()
Me.New(0)
End Sub
Public Sub New(ByVal columnIndex As Integer)
Me.New(columnIndex, ListViewColumnDataType.String)
End Sub
Public Sub New(ByVal columnIndex As Integer, ByVal dataType As ListViewColumnDataType)
Me.columnIndex = columnIndex
Me.dataType = dataType
End Sub
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
Dim str1 As String = CType(x, ListViewItem).SubItems(Me.columnIndex).Text
Dim str2 As String = CType(y, ListViewItem).SubItems(Me.columnIndex).Text
Select Case Me.dataType
Case ListViewColumnDataType.String
Return String.Compare(str1, str2)
Case ListViewColumnDataType.Integer
Dim int1 As Integer
Dim int2 As Integer
If Integer.TryParse(str1, int1) AndAlso Integer.TryParse(str2, int2) Then
Return int1 - int2
Else
Return String.Compare(str1, str2)
End If
Case ListViewColumnDataType.Date
Dim dt1 As Date
Dim dt2 As Date
If Date.TryParse(str1, dt1) AndAlso Date.TryParse(str2, dt2) Then
Return Date.Compare(dt1, dt2)
Else
Return String.Compare(str1, str2)
End If
End Select
End Function
End Class
Obviously you can add as many different data types as you need. You may also be interested to know that the ExtendedListView control in the WFC library in my signature supports complex data-binding, something like what DataGrids do, as well as having in-built sorting support.
Last edited by jmcilhinney; Jul 5th, 2006 at 04:30 AM.
-
Jul 5th, 2006, 06:37 AM
#4
Thread Starter
New Member
Re: ListViewSorter Class - there must be a better way to do this?
I was looking for a generic solution and you have found one for me in using that ExtendedListView control.
Thanks for your help.
-
May 16th, 2008, 02:21 PM
#5
Fanatic Member
Re: ListViewSorter Class - there must be a better way to do this?
I've just stumbled across this as I was wondering how to sort integer and dates. I have one other question though. It only sorts Ascendingly. What needs to be changed to sort Descending if it's already in Ascending and vice-versa?
ManagePC - the all-in-one PC management and inventory tool
-
May 16th, 2008, 03:08 PM
#6
Fanatic Member
Re: ListViewSorter Class - there must be a better way to do this?
I figured it out myself. Quite chuffed too!
Code:
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
Dim str1 As String = CType(x, ListViewItem).SubItems(Me.columnIndex).Text
Dim str2 As String = CType(y, ListViewItem).SubItems(Me.columnIndex).Text
Dim lv as ListView = Ctype(x,ListViewItem).ListView
Select Case Me.dataType
Case ListViewColumnDataType.String
if lv.sorting=SortOrder.Ascending Then
Return String.Compare(str1, str2)
Else
Return String.Compaure(str2,str1)
.
.
.
.
End Select
End Function
ManagePC - the all-in-one PC management and inventory tool
-
May 16th, 2008, 03:10 PM
#7
Frenzied Member
Re: ListViewSorter Class - there must be a better way to do this?
Just reverse the order of the items. Thus the first item will become last, and the last one will become first, and voila, it's sorted Descendingly.
Please rate helpful ppl's posts. It's the best 'thank you' you can give 
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|