在C#中按多列对ListView进行排序

时间:2009-10-22 11:40:27

标签: c# sorting listview controls

使用ListView控件,您可以指定要排序的列,并且可以随时使用sort()的方法。

但是,这只允许单列排序。

我很想排序,首先是A列,然后是F列,它们是相同的。

我发现了一些在线编写的自定义比较类,但想知道stackoverflow是否可以显示更清晰的方式。再加上这个可以帮助其他人在将来寻找它:)

有关如何理解此事的任何建议或示例。

6 个答案:

答案 0 :(得分:5)

所以,在玩完之后,我想出的答案是通过ListViewItemComparer界面写一个IComparer课程。

然后我覆盖了Compare()方法,现在可以返回-1,0或1,具体取决于第一列与第二列之间的比较,然后等于第二列。

最后我觉得很干净。

答案 1 :(得分:2)

与几乎所有任务一样,ObjectListView(.NET WinForms ListView的开源包装器)使得使用ListView变得更加容易。

ObjectListView具有SecondarySortColumnSecondarySortOrder属性,可以完全按照您的要求进行操作。

如果您想进行更好的排序,可以安装CustomSorter。看看this recipe

答案 2 :(得分:2)

@MarkMayo,我通过支持二级/优先级列排序的ListViewItemComparer接口创建了自己的排序器类IComparer

我覆盖Compare()方法以支持数字,日期和广告不区分大小写的字符串比较。

首先对您希望的列进行排序,如果两个比较值相同,则将第二列作为排序的参考,从而进行二次排序。

您只需要包含此分拣机类并使用以下示例VB.Net代码修改Form的Listview ColumnClick事件:

ListViewItemComparer类

Imports System.Collections

''' <summary>
''' This class is an implementation of the 'IComparer' interface.
''' </summary>
Public Class ListViewColumnSorter
    Implements IComparer
    ''' <summary>
    ''' Specifies the column to be sorted
    ''' </summary>
    Private ColumnToSort As Integer
    ''' <summary>
    ''' Specifies the secondary column to be sorted
    ''' </summary>
    Private SecondaryColumnToSort As Integer = -1
    ''' <summary>
    ''' Specifies the order in which to sort (i.e. 'Ascending').
    ''' </summary>
    Private OrderOfSort As SortOrder
    ''' <summary>
    ''' Class constructor. Initializes various elements
    ''' </summary>
    Public Sub New(ByVal column_number As Integer, ByVal sort_order As SortOrder)
        ColumnToSort = column_number
        OrderOfSort = sort_order
    End Sub
    ''' <summary>
    ''' Class constructor. Initializes various elements
    ''' </summary>
    Public Sub New(ByVal column_number As Integer, ByVal sort_order As SortOrder, ByVal secondary_column_number As Integer)
        ColumnToSort = column_number
        SecondaryColumnToSort = secondary_column_number
        OrderOfSort = sort_order
    End Sub

    ''' <summary>
    ''' This method is inherited from the IComparer interface. It compares the two objects passed and support secondary column comparison
    ''' </summary>
    ''' <param name="x">First object to be compared</param>
    ''' <param name="y">Second object to be compared</param>
    ''' <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
    Public Function Compare(x As Object, y As Object) As Integer Implements IComparer.Compare
        Dim compareResult As Integer
        Dim listviewX As ListViewItem, listviewY As ListViewItem

        ' Cast the objects to be compared to ListViewItem objects
        listviewX = DirectCast(x, ListViewItem)
        listviewY = DirectCast(y, ListViewItem)

        ' Compare the two items
        Dim x1 As Object = listviewX.SubItems(ColumnToSort)
        Dim y1 As Object = listviewY.SubItems(ColumnToSort)

        ' Use .tag for comparison if not empty
        If (x1.Tag IsNot vbNullString) And (y1.Tag IsNot vbNullString) Then
            compareResult = ObjectComparer(x1.Tag, y1.Tag)
        Else
            compareResult = ObjectComparer(x1.Text, y1.Text)
        End If

        'require secondary column compare?
        If (compareResult = 0 And SecondaryColumnToSort >= 0 And SecondaryColumnToSort <> ColumnToSort) Then
            ' Compare the two items
            Dim x2 As Object = listviewX.SubItems(SecondaryColumnToSort)
            Dim y2 As Object = listviewY.SubItems(SecondaryColumnToSort)

            ' Use .tag for comparison if not empty
            If (x2.Tag IsNot vbNullString) And (y2.Tag IsNot vbNullString) Then
                compareResult = ObjectComparer(x2.Tag, y2.Tag)
            Else
                compareResult = ObjectComparer(x2.Text, y2.Text)
            End If
        End If

        ' Calculate correct return value based on object comparison
        If OrderOfSort = SortOrder.Ascending Then
            ' Ascending sort is selected, return normal result of compare operation
            Return compareResult
        ElseIf OrderOfSort = SortOrder.Descending Then
            ' Descending sort is selected, return negative result of compare operation
            Return (-compareResult)
        Else
            ' Return '0' to indicate they are equal
            Return 0
        End If
    End Function

    ''' <summary>
    ''' This method compares the two objects passed. Object supported are numeric, dates and string
    ''' </summary>
    ''' <param name="x">First object to be compared</param>
    ''' <param name="y">Second object to be compared</param>
    ''' <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
    Private Function ObjectComparer(x As Object, y As Object) As Integer
        Dim compareResult As Integer

        If IsNumeric(x) And IsNumeric(y) Then 'comparing numbers
            compareResult = Val(x).CompareTo(Val(y))
        ElseIf IsDate(x) And IsDate(y) Then 'comparing dates
            compareResult = DateTime.Parse(x).CompareTo(DateTime.Parse(y))
        Else 'comparing string
            Dim ObjectCompare As New CaseInsensitiveComparer
            compareResult = ObjectCompare.Compare(x.ToString, y.ToString)
        End If
        Return compareResult
    End Function

End Class

Windows窗体的Listview ColumnClick

Private prevColumnClick As Integer 'to store previous sorted column number
Private secondary_column_to_sort As Integer = 0 'column 0

Private Sub lvLog_ColumnClick(sender As Object, e As ColumnClickEventArgs) Handles lvLog.ColumnClick
    Dim myListView As ListView = DirectCast(sender, ListView)
    Dim sort_order As System.Windows.Forms.SortOrder

    If myListView.Columns(e.Column).Tag Is Nothing Then
        sort_order = SortOrder.Ascending
    Else
        ' Get previous sort order information from columns .tag
        sort_order = DirectCast(myListView.Columns(e.Column).Tag, System.Windows.Forms.SortOrder)
    End If

    If (prevColumnClick = e.Column) Then
        If sort_order = SortOrder.Ascending Then
            sort_order = SortOrder.Descending
        Else
            sort_order = SortOrder.Ascending
        End If
    End If

    ' Initialize ColumnSorter class
    myListView.ListViewItemSorter = New ListViewColumnSorter(e.Column, sort_order, secondary_column_to_sort)

    ' Perform the sort with these new sort options.
    'myListView.Sort()

    ' Store current column sorting order
    myListView.Columns(e.Column).Tag = sort_order

    ' Store previous column number clicked 
    prevColumnClick = e.Column

End Sub

答案 3 :(得分:1)

这可能不是最有效的方式,但您可以执行以下操作:

listView.Sort(5);    // Column F, then
listView.Sort(0);    // Column A

请注意反向排序。

答案 4 :(得分:0)

这是在网上还是winform?在网络上,您可以将包含以逗号分隔的列和pass it to the sort() method of the listview

的表达式放在一起

框架3.5及以上......

答案 5 :(得分:0)

好吧,如果您只想对列进行排序,请尝试使用List of List;例如如下:

List<List<string>> lstColumns = new List<List<string>>();

没有尝试过,只是想快速解决。