Gruppierte Liste und MVVM

In meiner heutigen Windows 8 Modern UI (METRO) Schulung, ging’s um grouped Lists für Listview oder auch Gridview. Ich verwende im meinen VB.NET Beispielen gerne deutschsprachige Namen um auf einen Blick erkennen zu können, was API und was eigener Code ist. Dabei ging es um Personen, die anhand des Geschlechts gruppiert werden sollen. Für Geschlecht habe ich aus irgendwelchen Gründen das Englische Sex genommen und wenn man das Gruppiert landet man schnell bei Variablen wie GruppenSex. Nicht wundern.

Mein Ziel war Gruppen und das Viewmodel in Einklang zu bringen. Zunächst das Model mit der zweiten Klasse um die erste zu gruppieren.

   1:  Public Class Personen
   2:      Public Property ID As Integer
   3:      Public Property Name As String
   4:      Public Property Sex As String
   5:  End Class
   6:  Public Class GruppeSex
   7:      Public Property Sex As String
   8:      Public Property Menge As List(Of Personen)
   9:  End Class

 

Im ViewModel werden dann Dummy Daten erstellt, die erfreulicherweise so auch im Designer gleich angezeigt werden.

   1:  Public Class PersonenVM
   2:      Public Sub New()
   3:          PersonenListe = New List(Of Personen)
   4:          PersonenListe.Add(New Personen With {.ID = 1, .Name = "Hannes", .Sex = "Mann"})
   5:          PersonenListe.Add(New Personen With {.ID = 2, .Name = "Maria", .Sex = "Mann"})
   6:          PersonenListe.Add(New Personen With {.ID = 3, .Name = "Maria", .Sex = "Frau"})
   7:          PersonenListe.Add(New Personen With {.ID = 4, .Name = "Marion", .Sex = "Frau"})
   8:          PersonenListe.Add(New Personen With {.ID = 5, .Name = "Franz", .Sex = "Mann"})
   9:          PersonenListe.Add(New Personen With {.ID = 6, .Name = "Hermann", .Sex = "Mann"})
  10:          PersonenListe.Add(New Personen With {.ID = 7, .Name = "Hanna", .Sex = "Frau"})
  11:          PersonenListe.Add(New Personen With {.ID = 8, .Name = "Hubert", .Sex = "Mann"})
  12:          PersonenListe.Add(New Personen With {.ID = 9, .Name = "Horst", .Sex = "Mann"})
  13:          PersonenListe.Add(New Personen With {.ID = 10, .Name = "Anna", .Sex = "Frau"})

Als öffentliche Eigenschaften gibt es die Personen und die Gruppieriung. Benötigt wird hier nur Gruppelist.

   1:  Property PersonenListe As List(Of Personen)
   2:  Property GruppeList As List(Of GruppeSex)

Achtung: wenn das Property fehlt oder in C# der Set und Get, handelt es sich um einen normale Eigenschaft, die in der Bindung unsichtbar bleibt. Ein häufiger Fehler, der auch bei den Teilnehmer dieses Trainings auftrat.

Um die Gruppierung der Daten zu erreichen kommt hier ein LINQ Statement im Konstruktur (nach den Dummy Daten) zum Einsatz.

   1:  Dim query = From item In PersonenListe
   2:                      Order By item.Sex
   3:                      Group item By Key = item.Sex Into g = Group
   4:                      Select New GruppeSex With {.Sex = Key, .Menge = g.ToList}
   5:  GruppeList = query.ToList

Nun geht es in den deklarativen XAML Teil. Das Viewmodel wird über den DataContext der Page zugewiesen und damit instanziiert. Dazu wird unbedingt die CollectionViewSource benötigt. Der wird dann aus dem Modell die passende Liste zugewiesen, gruppierung angeschalten und der Pfad für die 1:n mit Item zugewiesen (aus der Klasse GruppeSex)

   1:  <Page.DataContext>
   2:          <local:PersonenVM></local:PersonenVM>
   3:  </Page.DataContext>
   4:  <Page.Resources>
   5:      <CollectionViewSource x:Name="cvs1" Source="{Binding GruppeList}"
   6:                          IsSourceGrouped="True" 
   7:                          ItemsPath="Menge"></CollectionViewSource>
   8:  </Page.Resources>

Ich gehe davon aus, das die Templating und Binding Konzepte von XAML bekannt sind. Die Besoderheit hier ist lediglich das GroupStyle Template für die Überschriften. Das Gridview Steuerelement bekommt aus dem CollectionViewsource die Daten zugewiesen (Staticresource weil in Resources deklariert) und Source statt Path, weil Liste. Im Kopf wird dann das Geschlecht angezeigt (aus der Klasse GruppeSex). Im Itemtemplate der Name (aus der Klasse Personen)

   1:  <GridView ItemsSource="{Binding Source={StaticResource cvs1}}"
   2:        HorizontalAlignment="Left" Margin="62,38,0,0" VerticalAlignment="Top" Width="961" Height="235">
   3:      <GridView.GroupStyle>
   4:          <GroupStyle>
   5:                <GroupStyle.HeaderTemplate>
   6:                     <DataTemplate>
   7:                         <TextBlock Text="{Binding Sex}" FontSize="42"></TextBlock>
   8:                     </DataTemplate>
   9:                </GroupStyle.HeaderTemplate>
  10:          </GroupStyle>
  11:      </GridView.GroupStyle>
  12:      <GridView.ItemTemplate>
  13:                  <DataTemplate>
  14:                      <TextBlock Text="{Binding  Name}" Width="100"></TextBlock>
  15:                  </DataTemplate>
  16:       </GridView.ItemTemplate>
  17:  </GridView>

Wirklich nett ist die sofortige Anzeige in Visual Studio 2013 oder Expression Blend.

image

Hinweis: Unter WinRT Windows 8 hat das geringfügig anders funktioniert.

Kommentare sind geschlossen