Mazliet par elementu kārtošanu. Nē, šis nebūs par ātriem kārtošanas algoritmiem, bet par saraksta sakārtošanu pēc paša noteiktas funkcijas.
Reizēm gadās situācija, ka ir dota Windows forma, uz kuras ListView kontrole. Kontrolē iekšā kaut kāds saraksts. Jānis Bērziņš, Pēteris Vītoliņš un visi pārējie. Vai arī “01.05.2004”, “03.02.2003” un citi. Kaut kādu ierakstu saraksts. Parasti gribas šādu sarakstu redzēt sakārtotu. Piemēram, augošā secībā pēc datumiem.
Tā tas gadījās arī man, vajadzēja sakārtot šādus Latvijā tik pierastā veidā noformatētus datumus (dd.MM.yyyy) augošā secībā. Skaidrs ir tas, ka, ja vienkārši ieslēgsim “Sort ascending” ListView kontrolei, datumi tiks sakārtoti apmēram šādā secībā – 01.01.2003; 01.02.2003; 02.01.2003, kas, protams, neatbilst mūsu vēlmei.
Ko darīt? Iejaukties elementu kārtošanas funkcijā.
Ja šādai kontrolei (kā ListView) ir ieslēgts Sort (asc/desc), tad pēc katra elementa pievienošanas tā sevī iekšienē izsauc Sort() funkciju. Sort funkcija pēc kaut kāda (mums nezināma) algoritma sakārto elementus pieprasītajā secībā. Taču skaidrs ir viens, ka neatkarīgi no izvēlētā kārtošanas algoritma (shell sort, quicksort, heapsort), Sort funkcijai būs nepieciešams salīdzināt divus elementus – “kas lielāks, zirgs vai 4nieks?”. Tātad, lai veidotu savu sakārtojumu ListView kontrolē, atliekt tikai piespiest tās kārtotāju izmantot kādu programmētāja definētu salīdzināšanas operāciju.
Šī vajadzība .NET arhitektūrā ir risināta ar IComparer interfeisa palīdzību. Interfeiss pieprasa implementēt vienu funkciju – Compare(x,y), kas atgriež negatīvu vērtību, ja x<y, pozitīvu vērtīby, ja x>y vai 0, ja x=y.
Jāatceras, ka Compare() tiks izsaukts tiem elementiem, ko mēģinām salīdzināt, nevis to labeliem, piemēram. Tas ir, ListView gadījumā mums jāveido funkcija, kas māk salīdzināt objektus ar tipu ListViewItem.
Izveidoju šādu klasi:
Public Class SimpleComparer
Implements IComparer
Public Function Compare(ByVal x As Object, ByVal y As Object) _
As Integer
Implements System.Collections.IComparer.Compare
Dim s1 As String = CType(x, ListViewItem).SubItems(0).Text
Dim s2 As String = CType(y, ListViewItem).SubItems(0).Text
Dim d1 As Date = DateSerial( _
CInt(Mid(s1, 7)), CInt(Mid(s1, 4, 2)), CInt(Mid(s1, 1, 2)))
Dim d2 As Date = DateSerial( _
CInt(Mid(s2, 7)), CInt(Mid(s2, 4, 2)), CInt(Mid(s2, 1, 2)))
Return Date.Compare(d1, d2)
End Function
End Class
Šeit SubItems(0) tiek lietots, lai norādītu kolonnu, pēc kuras jāsalīdzina. Kā zināms, ListViewItem var saturēt vairākas datu kolonnas – piemēram, to bieži var redzēt Windows Explorer logā, kad ieslēgts “Detail view”.
Tātad tagad mums ir savs salīdzinātājs. Diemžēl neviens to neizmanto : ( Ko darīt – rakstīt savu ListView klasi (mantotu no Windows.Forms.ListView), kas izmanto tieši šo salīdzinātāju. To darīju šādi:
Public Class MyListView
Inherits Windows.Forms.ListView
Private ocComparer As SimpleComparer
Public Sub New()
ocComparer = New SimpleComparer
Me.ListViewItemSorter = ocComparer
Me.Sorting = SortOrder.Ascending
End Sub
End Class
Tagad ir izveidota ListView klase, kas elementu salīdzināšanai izmanto savu salīdzināšanas funkciju. Atliek vien to ielikt kādā savā formā un lietot uz nebēdu.