powered by simpleCommunicator - 2.0.55     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сортировка в Lisview (.Net,объектный, details )
2 сообщений из 2, страница 1 из 1
Сортировка в Lisview (.Net,объектный, details )
    #38889780
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Один раз давно занимался
Вот вставил сейчас.
Public lvwColumnSorter As ListViewColumnSorter
...
Инициализация грубо:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
    lvwColumnSorter = New ListViewColumnSorter()
    ListViewInbox.ListViewItemSorter = lvwColumnSorter
...
    lvwColumnSorter_Inbox.SortColumn = StartParam.SortColumn
    If StartParam.SortOrder = SortOrder.Ascending Then
      lvwColumnSorter.Order = SortOrder.Ascending
    Else
      lvwColumnSorter.Order = SortOrder.Descending
    End If



Класс ListViewColumnSorter (как есть сейчас):
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
Imports System.Windows.Forms

Public Class ListViewColumnSorter
  Implements IComparer
  ' Specifies the column to be sorted
  Private ColumnToSort As Integer
  ' Specifies the order in which to sort (i.e. 'Ascending').
  Private OrderOfSort As SortOrder
  ' Case insensitive comparer object
  Private ObjectCompare As CaseInsensitiveComparer

  ' Class constructor.  Initializes various elements
  Public Sub New()
    ' Initialize the column to '0'
    ColumnToSort = 0
    ' Initialize the sort order to 'none'
    OrderOfSort = SortOrder.None
    ' Initialize the CaseInsensitiveComparer object
    ObjectCompare = New CaseInsensitiveComparer()
  End Sub

  ' This method is inherited from the IComparer interface.
  ' It compares the two objects passed using a case insensitive comparison.
  ' <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(ByVal x As Object, ByVal y As Object) As Integer _
    Implements IComparer.Compare
    Dim compareResult As Integer
    Dim listviewX, listviewY As ListViewItem

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

    ' Compare the two items
    compareResult = ObjectCompare.Compare(listviewX.SubItems(ColumnToSort).Text,
                                          listviewY.SubItems(ColumnToSort).Text)

    ' 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

  ' Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
  Public Property SortColumn() As Integer
    Set(ByVal value As Integer)
      ColumnToSort = value
    End Set
    Get
      Return ColumnToSort
    End Get
  End Property

  ' Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
  Public Property Order As SortOrder
    Set(ByVal value As SortOrder)
      OrderOfSort = value
    End Set
    Get
      Return OrderOfSort
    End Get
  End Property

End Class



Щелчки по столбцам(грубо).

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
  Private Sub ListView1_ColumnClick(sender As Object, e As ColumnClickEventArgs) Handles ListView1.ColumnClick
 
    Dim SK As Integer = lvwColumnSorter.SortColumn 'запоминаем предыдущий ключ сортировки
    If e.Column = Column_Icon.Index Then Exit Sub 'сортировку по иконке не производим
    If (SK = e.Column) Then 'ключ сортировки не меняется,меняем порядок сортировки
      If lvwColumnSorter.Order = SortOrder.Ascending Then
        lvwColumnSorter.Order = SortOrder.Descending
        'установка иконки "Descending"
        ...
       Else
        lvwColumnSorter_Inbox.Order = SortOrder.Ascending
        'установка иконки "Ascending"
         ...
    Else 'если ключ сортировки меняется, порядок сортировки делаем по возрастанию
      lvwColumnSorter.Order = SortOrder.Ascending
      lvwColumnSorter.SortColumn = e.Column
      'удаление предыдущей иконки
      'установка иконки "Ascending"
        ...
     End If
    ListView1.Sort()
  End Sub



Предварительно мне нравится как это работает.

Пока такие вопросы соображения
1) Как мне лучше изменить мой ListViewColumnSorter класс (спойлер выше) чтоб иметь возможность сортировать по дата/время.
Так понимаю задать параметр SortMethod (string/date) и в зависимости от него использовать разные Compare в "Function Compare"?
Не подскажете как лучше? Примеры смотрел, не везде кстати CaseInsensitiveComparer используется. Как бы его вообще соптимизировать по скорости?
2) Насколько хороша эта "автоматика"? Я так понимаю что нек. время затрачивается на инициализацию ListViewColumnSorter а при добавлении записи уже втыкаются на свое место.
Т.е. не будет ли это тормозить при добавлении большого к-ва записей.

Для сравнения, подобная сортировка "c API Listview" занимает время при каждом .Sort(), тычки по столбцам в этой модели занимают нулевое время. Поэтому в API я делал Sort() только при необходимости (при загрузке списка и при щелчках по столбцам, новые записи тупо добавлял вверх списка).

Как -то надо в это врубиться в общем, потом уже миллисекунды считать и оптимизировать.

P.S. Не стал писать в соседнюю тему, замусорили ее сильно, хотя это к ней относится.
...
Рейтинг: 0 / 0
Сортировка в Lisview (.Net,объектный, details )
    #38891197
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77,

1) Как мне лучше изменить мой ListViewColumnSorter класс (спойлер выше) чтоб иметь возможность сортировать по дата/время.
Так понимаю задать параметр SortMethod (string/date) и в зависимости от него использовать разные Compare в "Function Compare"?
Не подскажете как лучше? Примеры смотрел, не везде кстати CaseInsensitiveComparer используется. Как бы его вообще соптимизировать по скорости?

Модернизировал чуть добавив TypeOfSort (String/Date)

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
    ' Compare the two items
    If TypeOfSort = eSortTypeConstants.stDate Then
      compareResult = DateTime.Compare(DateFromString(listviewX.SubItems(ColumnToSort).Text),
                                       DateFromString(listviewY.SubItems(ColumnToSort).Text))
    Else
      compareResult = ObjectCompare.Compare(listviewX.SubItems(ColumnToSort).Text,
                                            listviewY.SubItems(ColumnToSort).Text)
    End If



Всякие CDate, IsDate -работают очень медленно, особенно если вызывать их по несколько раз при каждом сравнении.
Генерировать Try/Catch как - в нек. документациях примеры видел -это вообще жопа полная.
Поэтому с учетом опыта воспользовался простенькой API-реализацией VarDateFromStr

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
  '!psDateIn - указатель на ЮНИКОД -строку, содержащую дата-время
  Public Declare Unicode Function VarDateFromStr Lib "oleaut32.dll" ( _
   ByVal psDateIn As String, _
   ByVal lcid As Integer, _
   ByVal uwFlags As Integer, _
   ByRef dtOut As Date) As Integer

  'National Language Support Functions
  Public Declare Function GetUserDefaultLCID Lib "kernel32" () As Integer

  Public Function DateFromString(ByVal sDateIn As String) As Date
    Dim hResult As Integer
    Dim dtOut As Date

    Const LOCALE_NOUSEROVERRIDE = &H80000000

    hResult = VarDateFromStr(sDateIn, GetUserDefaultLCID(), LOCALE_NOUSEROVERRIDE, dtOut)
    Return dtOut
  End Function


В случае ошибки hResult<>S_OK DateFromString быстро вернет пустую дату "0:00:00", что не вызовет исключений и не помешает сортировке.
Здесь небольшая просадка по скорости из за того что передаю в VarDateFromStr sDateIn As String (ну а как иначе из объектной то модели, в VB6 я передавал hMem -указатель на память).
Но с лихвой компенсируется тем, что DateTime.Compare работает очень быстро в отличии от
Format$ (DateFromString(hMem), "yyyymmddhhmmss")) который я использовал в VB6.
Во всяком случае в .Net такой "Format" дает тормоза.

Ну т.е. в итоге я получил
около 280мс при сортировке 10000 записей по столбцу с дата/время в .Net-Listview
против 170-190мс для 6500 записей в API-Listview. 15067121
Тоже самое -считаю результат удовлетворительным.

m-m-m..API-тест перепроверить бы надо, при том тесте комп был другой, более старый....


На всякий случай прилагаю свой ListViewColumnSorter, как он есть сейчас.

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
Imports System.Windows.Forms

Public Class ListViewColumnSorter
  Implements IComparer

  Public Enum eSortTypeConstants
    [stString] = 0
    [stStringSensitive] = 1
    [stNumeric] = 2
    [stDate] = 3
  End Enum

  ' Specifies the column to be sorted
  Private ColumnToSort As Integer
  ' Specifies the order in which to sort (i.e. 'Ascending').
  Private OrderOfSort As SortOrder
  ' Case insensitive comparer object
  Private ObjectCompare As CaseInsensitiveComparer
  ' Sort Type
  Private TypeOfSort As eSortTypeConstants

  ' Class constructor.  Initializes various elements
  Public Sub New()
    ' Initialize the column to '0'
    ColumnToSort = 0
    ' Initialize the sort order to 'none'
    OrderOfSort = SortOrder.None
    ' Initialize the CaseInsensitiveComparer object
    ObjectCompare = New CaseInsensitiveComparer()
    ' Initialize the sort type to [stString]'
    TypeOfSort = eSortTypeConstants.stString
  End Sub

  Public Sub New(ByVal column As Integer, ByVal order As SortOrder, Optional ByVal type As eSortTypeConstants = eSortTypeConstants.stString)
    ColumnToSort = column
    OrderOfSort = order
    TypeOfSort = type
    ObjectCompare = New CaseInsensitiveComparer()
  End Sub

  ' This method is inherited from the IComparer interface.
  ' It compares the two objects passed using a case insensitive comparison.
  ' <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(ByVal x As Object, ByVal y As Object) As Integer _
    Implements IComparer.Compare
    Dim compareResult As Integer
    Dim listviewX, listviewY As ListViewItem

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

    ' Compare the two items
    If TypeOfSort = eSortTypeConstants.stDate Then
      compareResult = DateTime.Compare(DateFromString(listviewX.SubItems(ColumnToSort).Text),
                                       DateFromString(listviewY.SubItems(ColumnToSort).Text))
    Else
      compareResult = ObjectCompare.Compare(listviewX.SubItems(ColumnToSort).Text,
                                            listviewY.SubItems(ColumnToSort).Text)
    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

  ' Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
  Public Property SortColumn() As Integer
    Set(ByVal value As Integer)
      ColumnToSort = value
    End Set
    Get
      Return ColumnToSort
    End Get
  End Property

  ' Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
  Public Property Order As SortOrder
    Set(ByVal value As SortOrder)
      OrderOfSort = value
    End Set
    Get
      Return OrderOfSort
    End Get
  End Property

  ' Gets or sets the type of sorting to apply (for example, '[stString]' or '[stDate]').
  Public Property SortType As eSortTypeConstants
    Set(ByVal value As eSortTypeConstants)
      TypeOfSort = value
    End Set
    Get
      Return TypeOfSort
    End Get
  End Property

End Class



2) Насколько хороша эта "автоматика"? Я так понимаю что нек. время затрачивается на инициализацию ListViewColumnSorter а при добавлении записи уже втыкаются на свое место.
Т.е. не будет ли это тормозить при добавлении большого к-ва записей.

Для сравнения, подобная сортировка "c API Listview" занимает время при каждом .Sort(), тычки по столбцам в этой модели занимают нулевое время. Поэтому в API я делал Sort() только при необходимости (при загрузке списка и при щелчках по столбцам, новые записи тупо добавлял вверх списка).

Насчет нулевого времени это я погорячился. Вполне конечное - типа значений что привел выше.
Если держать Listview отсортированным т.е с привязанным к нему lvwColumnSorter, то при добавлении в отсортированный 10000 записей он рискует уже не проснуться.
Надо вызывать сортировку только при необходимости, например после полной загрузки списка или при щелчке по столбцу.
Часто встречаемые примеры кода, где каждый раз вызывается New ListViewColumnSorter() без сохранения этого New не прокатили.

"Ручная" сортировка делается так:
Код: vbnet
1.
2.
3.
4.
    'начало сортировки
    ListView1.ListViewItemSorter = lvwColumnSorter 'эта команда сортирует
    ListView1.ListViewItemSorter = Nothing 'отменяем авто-сортировку
    'конец сортировки



Ну и до кучи, если например полностью обновлять содержимое (кнопка Refresh), то вот такие хорошие команды например
Код: vbnet
1.
2.
3.
4.
5.
    ListView1.Items.Clear() 
    ListView1.Update() 'визуально очистить
    ListView1.BeginUpdate()
....многочисленные действия типа AddItem()
    ListView1.EndUpdate()



Продолжая начатую тему, предварительно я объектной .Net моделью Listview доволен, просадка скорости по сравнению с API если и есть, то 10-15% не более, это не критично и думаю можно чуть оптимизировать при желании.

===
P.S. Гораздо большие тормоза дает позднее связывание ADODB при чтении из БД. Счас пока разбираюсь с ранним связыванием. Плюс еще какие-то мелкие ф-ции типа IsDate, IsDbNull, Format и т.п. скорость просаживают.

Т.е. получается при тестовой загрузке 10000 строк в ListView
API: 2050мс -из них 1450мс -работа с ListView включая сортировку по датам, 600мс - чтение из БД и т.п.
Net: 3800мс -из них 1650мс -работа с ListView включая сортировку по датам, 2150мс - чтение из БД и т.п.

Позднее связывание adodb жрет секунду.
...
Рейтинг: 0 / 0
2 сообщений из 2, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сортировка в Lisview (.Net,объектный, details )
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]