Listbox lietojumi

Iepriekšējā rakstā minēju, ka “esam mantojuši ListView klasi, atliek tikai to izmantot”. Te nu jautāums, kā to izdarīt.
MS Visual Studio 2003 gada versija pagaidām nepiedāvā iespeju, vismaz – ne acīmredzami. Ir iespēja uz formas novietot gatavas kontroles, ir iespēja gatavās kontroles “ievilkt iekš toolbox-a”, bet nav iespējas iestāstīt VStudio, ka šī tava klase ir patiesībā mantota no windows formām un ka tā ir vizuāla un ka tai ir design-time interfeiss kā jau kārtīgai ActiveX kontrolei.
Tāpēc pagaidām rīkojos tā: uz formas novietoju to kontroli, no kuras esmu mantojis savu klasi. Piemēram, ja man vajag uz formas uzlikt MyListView:Widnows.Forms.ListView, tad uz formas uzlieku pašu ListView elementu. Pēc tam atveram formu dizainera ģenerēto kodu.
Kaut kur tajā kodā atrodam rindu:

Friend WithEvents ListView1 As System.Windows.Forms.ListView
Šajā vietā aizvietojam “System.Windows.Forms.ListView” ar “MyListView”.
Pēc tam pameklējam nedaudz tālāk un atrodam
Me.ListView1 = New System.Windows.Forms.ListView
, kur veicam analoģisku aizvietojumu.
Tālākais arī nav gluži acīmredzams. Nospiežam Save. Aizveram formu dizaineri. Aizveram pašu formu. Uztaisām projektam “rebuild”. Atveram formu dizaineri. Vizuāli nekas nav mainījies (jo design-time interfeisu taču neesam mainījuši), bet kontroles tips ir no Windows.Forms.ListView pārvērties par MyListView, kas arī bija vajadzīgs.
Jaunajā VStudijas versijā ir paredzēta vienkāršota kontroļu tipu maiņa, kur šādas izmaiņas būs veicamas ar vienu klikšķi. Viens “+” punkts jaunajai studijai.

Kārtošana un IComparer

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.