Simple Listview sorting by columns

  • (2 Pages)
  • +
  • 1
  • 2

17 Replies - 35632 Views - Last Post: 23 February 2019 - 05:41 PM Rate Topic: ***** 2 Votes

#16 andrewsw   User is offline

  • quantum multiprover
  • member icon

Reputation: 6776
  • View blog
  • Posts: 27,943
  • Joined: 12-December 12

Re: Simple Listview sorting by columns

Posted 21 February 2015 - 08:10 PM

Thanks IronRazer

Let me see if this is animated:

Attached Image
Was This Post Helpful? 0
  • +
  • -

#17 ljwheeler   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 23-February 19

Re: Simple Listview sorting by columns

Posted 23 February 2019 - 05:16 PM

View PostIronRazer, on 21 February 2015 - 07:18 PM, said:

Here is my take on a sorting class. It will sort in Ascending or Descending order and will also sort the columns according to the type of string data in them.

For example if column 1 has Names (String Data), Column 2 has Ages (Integer Data), and column 3 has Dates like "04/11/2015" then the sorter class will determine that and sort it according to the Date.

Public Class ListViewColumnSorter
    Implements System.Collections.IComparer

    Private _ColumnIndex As Integer
    Private _SortingOrder As SortOrder
    Private ItemComparer As CaseInsensitiveComparer

    Public Sub New()
        _ColumnIndex = 0
        _SortingOrder = SortOrder.None
        ItemComparer = New CaseInsensitiveComparer()
    End Sub

    Public Property ColumnIndex() As Integer
        Get
            Return _ColumnIndex
        End Get
        Set(ByVal Value As Integer)
            _ColumnIndex = Value
        End Set
    End Property

    Public Property SortingOrder() As SortOrder
        Get
            Return _SortingOrder
        End Get
        Set(ByVal Value As SortOrder)
            _SortingOrder = Value
        End Set
    End Property

    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare
        Dim compareResult As Integer
        Dim LviStrX As String = DirectCast(x, ListViewItem).SubItems(_ColumnIndex).Text
        Dim LviStrY As String = DirectCast(y, ListViewItem).SubItems(_ColumnIndex).Text

        Dim numX, numY As Integer
        Dim dtX, dtY As Date

        If Integer.TryParse(LviStrX, numX) AndAlso Integer.TryParse(LviStrY, numY) Then
            compareResult = ItemComparer.Compare(numX, numY)
        ElseIf Date.TryParse(LviStrX, dtX) AndAlso Date.TryParse(LviStrY, dtY) Then
            compareResult = ItemComparer.Compare(dtX, dtY)
        Else
            compareResult = ItemComparer.Compare(LviStrX, LviStrY)
        End If

        If _SortingOrder = SortOrder.Ascending Then
            Return compareResult
        ElseIf _SortingOrder = SortOrder.Descending Then
            Return -compareResult
        Else
            Return 0
        End If
    End Function
End Class




Then in the form you can use it like shown in the ColumnClick event. I used a listview with 3 columns added to it in this example. The first time the header is clicked it will sort in Ascending order and the second time it sorts in Descending order. It will switch back and forth on each click after that.
Public Class Form1
    Dim r As New Random

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim names() As String = {"Andrew", "Roy", "John"}
        Dim ages() As String = {"40", "13", "48"}
        For i As Integer = 0 To names.Length - 1
            Dim lvi As ListViewItem = ListView1.Items.Add(names(i))
            lvi.SubItems.Add(ages(i))
            lvi.SubItems.Add(Now.AddDays(r.Next(0, 50)).ToShortDateString)
        Next
        For Each c As ColumnHeader In ListView1.Columns
            c.Tag = SortOrder.None
        Next
    End Sub

    Private Sub ListView1_ColumnClick(ByVal sender As Object, ByVal e As System.Windows.Forms.ColumnClickEventArgs) Handles ListView1.ColumnClick
        Dim iSortOrder As SortOrder = CType(ListView1.Columns(e.Column).Tag, SortOrder)
        Dim lvcs As New ListViewColumnSorter
        If iSortOrder = SortOrder.Ascending Then
            ListView1.Columns(e.Column).Tag = SortOrder.Descending
            lvcs.SortingOrder = SortOrder.Descending
        Else
            ListView1.Columns(e.Column).Tag = SortOrder.Ascending
            lvcs.SortingOrder = SortOrder.Ascending
        End If
        lvcs.ColumnIndex = e.Column
        ListView1.ListViewItemSorter = lvcs
    End Sub
End Class



Attachment sort.gif


This solution works great until you populate the ListView control with new data.

  • If _ColumnIndex = 0 and _SortingOrder was changed prior to new data population, only item 0 contains data in all columns whereas items 1-n only contains data in column 0 (all subsequent columns are empty).
  • If _ColumnIndex > 0 and _SortingOrder was changed prior to new data population, the Compare function throws an 'System.ArgumentOutOfRangeException' in System.Windows.Forms.dll exception.

Was This Post Helpful? 0
  • +
  • -

#18 IronRazer   User is offline

  • Custom Control Freak
  • member icon

Reputation: 1535
  • View blog
  • Posts: 3,864
  • Joined: 01-February 13

Re: Simple Listview sorting by columns

Posted 23 February 2019 - 05:41 PM

@ ljwheeler,
Perhaps if you asked a new question and supplied the code you are using to populate the listview, or a simple example code which allows us to reproduce the same problem, we would be able to suggest a fix. Also, include the full exception messages that you get and which line they are raised on. I am getting ready to get off the computer for tonight though, so I can try looking at it tomorrow at some point. 8)
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2