ListView sorting question

Hi

I have a ListView control called HSlist on a form which has 3 columns. The adding data seems to work OK, but the sorting is weird to say the least.

Initially, I thought that the list would be sorted on the contents in the first column, so I added to the ListView with the Item containing the data that I wanted the list to be sorted on (numerical). Then I found that the list was being sorted on the second column (strings), so I swapped the adding routine so that the numerical data was now in the second column - the list now was being sorted on the first column (strings).

What I want, is either to be able to dictate which column the list is to be sorted on, or, some other way of sorting on the numerical data column.

Here is what I use to add data to the list:

Dim freddy As New ListViewItem(Name.Text, 0) 'what's the zero for
freddy.SubItems.Add(Score.Text)
freddy.SubItems.Add(Now())
HSlist.Sorting = SortOrder.Descending
HSlist.Items.Add(freddy)




Answer this question

ListView sorting question

  • mendez_edd

    Leshay....

    What Datatype are you using in the listview elements for date

    My guess is that you are using a string.... that routine looks as if it's using a decimaltime. (A Double precision number)

    That's way it's not working and definitely why I think you should be using a sting sort on that data type....



  • remy_tache

    You will need to do some more work to accomplish what you want. It is all described in the ListView.Sort method msdn article

    http://msdn.microsoft.com/vstudio/express/visualcsharp/starterkit/#blackjack

    Typically items are sorted using the Sorting property, which sorts items based on the item text. To customize the sort order, you must write a class that implements the IComparer interface and set the ListViewItemSorter property to an object of that class. This is useful, for example, when you want to sort items by subitem text. For more information on performing manual sorting of items, see the example for the ListViewItemSorter property.



  • Lck

    I am very sorry, my keyboard does not seem to want to cut and paste the links I want. I will not blame the keyboard, I should have seen that the link was incorret. It was for another reply.

    http://msdn2.microsoft.com/en-us/library/system.windows.forms.listview.sort.aspx

    This is the link, it will explain more what you need to do and hopefully it will cover you question, if not you are more than welcome to post more questions here.



  • DirkW

    Thanks for the pointer to Sorting (Sort didn't seem to find that).

    The link you gave seems to be for C# coding rather than VB, so I didn't download it.

    The Sorting/ListViewSorter stuff may invoke more questions from me though :)



  • Sergio Gama

    Whoa!!!!!!

    The good news about the Tag property is that it's an object and you can put anything in it  you wish. The bad news about the Tag property is that it's an object and you can put anything in it  you wish.

    Quotes specify a string datum and that what that code is looking for. Let me look at how the wrong columns could possibly be happening. Yes the quotes matter. Always use the quotes.

     



  • AsimK

    Hi

    Thanks for routine. I can get it to work on 2 of my three columns. Col1 is string, col2 is numeric and the third is date (formatted like this 10/02/1930).

    I get a run time error when clicking on the date col header, at the following line:

    Result = Decimal.Compare(CType(ItemX.SubItems(mSortColumn).Text, Decimal), CType(ItemY.SubItems(mSortColumn).Text, Decimal))

    reporting Conversion from string "04/16/1947" to type 'Decimal' is not valid.

    I was using British formatted dates, but when I got the error on the date field I tried American format but that still produces the error.

    Perhaps the format is still incorrect Any ideas



  • ccdev

    OK, that article seems to be a better explanation (from a quick scan). I will need to read and digest.

  • asiaenforcer

    The code snippet your last post looks identical to the code I am trying to use. It seems the same as the full Class you posted earlier - unless you know differently

    With my limited understanding, and trying to trace the flow, it definately doesn't like something about casting

    ItemX.SubItems(mSortColumn).Text - which equals "09/10/2002" to DateTime type.

    or

    ItemX.SubItems(mSortColumn).Text = "02/09/2006" to DateTime type.

    I tried inserting

    Dim xx

    xx = CType(ItemX.SubItems(mSortColumn).Text, DateTime)

    above the offending line, and this caused the same error. Not entirely sure as to the analysis of that fact, except to say - it didn't work :)



  • codepath

    First of all, I'm as impressed as I can be that you've gotten that far in such a short amount of time. Let me study it a but.....

    I can't tell you how hard that was for me when I first did Dot Net.

    Try this.... try assigning the column to a string value.... it should still sort. See what happens.



  • Bhavtosh

    This article might be intersting for you, a bit old but it should still apply.

    http://msdn.microsoft.com/library/default.asp url=/library/en-us/dnwinforms/html/listviewsort.asp



  • MarcLile

    I'm not sure that I have altered things 'cleanly', but changing the tag to "string" for the date column doesn't crash anymore, and there is some sorting taking place.

    Clicking on col 1 header sorts on col 1 - as does clicking on col 2 which sorts on col 2.

    However, when clicking on the Date column header (col 3), it is sorting on col 1 (string) instead of column 3 (Date).

    Does the date format matter

    Also, where, for example, the code has

    .Columns(1).Tag = "Numeric" does that insert the quotes also, because the tag field seems to accept either with or without quotes - and does it matter



  • KENMx

     

    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

    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

     

     I'd pay a lot of attention to the red.....

     



  • Jaisheel

     

    I did a project on this when I began in Dot Net and I learned a lot of things. MANY users had issues and failures with standard Microsoft Techniques. After a lot of research I found this.. and modified it:

    There's are a twist to it. In the .Tag property of each column you specifiy the datatype of the column: "Numeric", "String" or "Date".

     

    Imports System.Collections

    Imports System.Windows.Forms

     

    Public Class Form1

     

        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

            '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 With

        End Sub

     

        'The 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 Sub

     

        'And then the class module.....

     

        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

                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

                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 Class

    End Class

     

    After having used this and never having seen it hiccup.... I'm really happy I did.

     



  • Scott Hathaway

    OK Andreas, thanks again.

    There sure is a lot of compexity involved just to sort what amounts to the equivalent of multi dimension array (in my opinion).

    Seems to me the ListView methods are lacking a simple sort - I had originally posted thinking that there would be. However, I'll have to bite the bullet and try to understand the Sorting stuff.



  • ListView sorting question