Сортировка ListView по нескольким столбцам в C # - PullRequest
2 голосов
/ 22 октября 2009

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

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

Я хочу отсортировать, скажем, сначала по столбцу А, а затем по столбцу F, когда они совпадают.

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

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

Ответы [ 6 ]

5 голосов
/ 28 октября 2009

Итак, поэкспериментировав, я пришел к ответу, написав класс ListViewItemComparer через интерфейс IComparer.

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

В конце концов, довольно аккуратно, я думаю.

2 голосов
/ 07 января 2014

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

Я перезаписываю Compare() метод для поддержки числового, нечувствительного к регистру сравнения строк.

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

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

ListViewItemComparer Class

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 FormClick

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
2 голосов
/ 23 октября 2009

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

ObjectListView имеет свойства SecondarySortColumn и SecondarySortOrder, чтобы точно выполнять то, что вы просите.

Если вы хотите сделать еще более интересную сортировку, вы можете установить CustomSorter. Взгляните на этот рецепт

1 голос
/ 20 января 2017

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

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

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

0 голосов
/ 22 октября 2009

Ну, если вы хотите, чтобы столбцы сортировались, попробуйте использовать Список из списка; например, как показано ниже:

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

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

0 голосов
/ 22 октября 2009

Это в сети или winform? В Интернете вы можете собрать выражение, в котором столбцы разделены запятыми, и передать его в метод sort () списка

.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...