2009-10-22 2 views
2

С помощью элементов управления ListView вы можете указать сортировку столбца, и есть метод, который должен быть sort() всякий раз, когда вы захотите.Сортировка ListView по нескольким столбцам в C#

Однако это разрешает только сортировку по одному столбцу.

Я стараюсь сортировать, скажем, сначала столбец A, а затем столбец F, если они одинаковы.

Я нашел несколько пользовательских классов сравнения, написанных в Интернете, но задался вопросом, может ли stackoverflow показать более чистый способ. Плюс наличие этого здесь может помочь другим, кто ищет его в будущем :)

Любые предложения или примеры того, как это сделать.

+1

Вы заполняете этот список через запрос? возможно, вы можете сохранить критерии сортировки в скрытом поле, а затем просто упорядочить по этим критериям в своем запросе. – jim

+0

К сожалению, нет. Данные попадают в список частично заполненных, а затем, когда информация о элементах известна, список обновляется - требуется прибегнуть к использованию в списке, поскольку они входят в ... –

ответ

5

Итак, после игры, я придумал, чтобы написать класс ListViewItemComparer через интерфейс IComparer.

Затем я переписал метод Compare() и теперь мог возвращать -1, 0 или 1 в зависимости от сравнения первого первичного столбца, а затем при равном вторичном столбце.

Достаточно аккуратный, в конце концов, я думаю.

+0

вы можете поделиться своим ListViewItemComparer класс здесь? Я столкнулся с той же проблемой и искал решение для сортировки моего ListView – Dennis

+0

@Dennis извините, оглядываясь назад, я должен был расширить свой ответ с помощью некоторого примерного кода, но это было несколько компаний агао и больше не имеет этого. Мои извинения. –

+0

Это не кажется слишком тривиальным; фактический метод сравнения никогда не получает полный объем, а всего два объекта для сравнения. – Nyerguds

0

Это в Интернете или winform? В Интернете вы можете собрать выражение, которое имеет столбцы, запятую и pass it to the sort() method of the listview

Framework 3.5 и выше, хотя ...

+0

Windows Form, спасибо, хотя –

0

Ну, если вы просто хотите столбцы для сортировки, попробуйте использовать список списка; например, следующие:

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

Не пробовал, а просто думал о быстром решении.

2

Как и почти все задачи, ObjectListView (оболочка с открытым исходным кодом вокруг .NET WinForms ListView) значительно облегчает жизнь с помощью ListView.

ОбъектListView имеет SecondarySortColumn и SecondarySortOrder свойства, чтобы сделать то, что вы просите.

Если вы хотите сделать еще более удобную сортировку, вы можете установить CustomSorter. Посмотрите на this recipe

2

@MarkMayo, я создал свой собственный сортировщик класса ListViewItemComparer через интерфейс IComparer, который поддерживает сортировку вторичных/приоритетных столбцов.

I overwrite Compare() метод поддержки числовых, дата & сравнение без учета регистра.

Сначала вы отсортируете нужный столбец, если оба сравниваемых значения совпадают, второй столбец будет использоваться для сортировки, а значит, и вторичной сортировки.

Вам просто нужно включить этот класс сортировщика и изменить событие List List ColumnClick в следующем примере VB.Чистый код:

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 Form в 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 
1

Это, вероятно, не самый эффективный способ, но вы можете просто сделать следующее:

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

Обратите внимание на обратный порядок.

Смежные вопросы