Results 1 to 7 of 7

Thread: ListViewSorter Class - there must be a better way to do this?

  1. #1

    Thread Starter
    New Member
    Join Date
    May 2003
    Posts
    10

    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

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    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.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: ListViewSorter Class - there must be a better way to do this?

    E.g.
    VB Code:
    1. Private Enum ListViewColumnDataType
    2.     [String]
    3.     [Integer]
    4.     [Date]
    5. End Enum
    6.  
    7. Private Class ListViewItemComparer
    8.     Implements IComparer
    9.  
    10.     Private columnIndex As Integer
    11.     Private dataType As ListViewColumnDataType
    12.  
    13.     Public Sub New()
    14.         Me.New(0)
    15.     End Sub
    16.  
    17.     Public Sub New(ByVal columnIndex As Integer)
    18.         Me.New(columnIndex, ListViewColumnDataType.String)
    19.     End Sub
    20.  
    21.     Public Sub New(ByVal columnIndex As Integer, ByVal dataType As ListViewColumnDataType)
    22.         Me.columnIndex = columnIndex
    23.         Me.dataType = dataType
    24.     End Sub
    25.  
    26.     Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
    27.         Dim str1 As String = CType(x, ListViewItem).SubItems(Me.columnIndex).Text
    28.         Dim str2 As String = CType(y, ListViewItem).SubItems(Me.columnIndex).Text
    29.  
    30.         Select Case Me.dataType
    31.             Case ListViewColumnDataType.String
    32.                 Return String.Compare(str1, str2)
    33.             Case ListViewColumnDataType.Integer
    34.                 Dim int1 As Integer
    35.                 Dim int2 As Integer
    36.  
    37.                 If Integer.TryParse(str1, int1) AndAlso Integer.TryParse(str2, int2) Then
    38.                     Return int1 - int2
    39.                 Else
    40.                     Return String.Compare(str1, str2)
    41.                 End If
    42.             Case ListViewColumnDataType.Date
    43.                 Dim dt1 As Date
    44.                 Dim dt2 As Date
    45.  
    46.                 If Date.TryParse(str1, dt1) AndAlso Date.TryParse(str2, dt2) Then
    47.                     Return Date.Compare(dt1, dt2)
    48.                 Else
    49.                     Return String.Compare(str1, str2)
    50.                 End If
    51.         End Select
    52.     End Function
    53. 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.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  4. #4

    Thread Starter
    New Member
    Join Date
    May 2003
    Posts
    10

    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.

  5. #5
    Fanatic Member
    Join Date
    Apr 2006
    Posts
    746

    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

  6. #6
    Fanatic Member
    Join Date
    Apr 2006
    Posts
    746

    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

  7. #7
    Frenzied Member obi1kenobi's Avatar
    Join Date
    Aug 2007
    Posts
    1,091

    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
  •  



Click Here to Expand Forum to Full Width