Noch immer experimentiere ich mit großen Datenmengen wie sie in typischen Geschäftsanwendungen vorkommen (LOB). Dabei werden viele Tausend Vornamen als Liste dargestellt. Meine Winrt Prototyp soll nun per Sematic Zoom eine Auswahl per Buchstaben ermöglichen, Ähnlich einem Reiter im Telefonbuch. Als Ausgangspunkt haben ich ein Beispiel aus dem METRO SDK genommen, das XAML grouped data controls sample. Das funktioniert zwar weder in der C# noch VB.NET Variante richtig, aber ist ein Code Beispiel.
Alles beginnt ganz harmlos mit einem sehr langem String Array
Dim sf = Await KnownFolders.DocumentsLibrary.GetFileAsync("vorname.txt")
Dim s As String = Await FileIO.ReadTextAsync(sf)
Dim liste As String() = s.Split(vbLf)
Jetzt wird's ein wenig kniffelig. Um im Semantic Zoom die gruppierte Sicht darstellen zu können, braucht man ein gruppierungsmerkmal. In meinem Fall der Anfangsbuchstabe. Allerdings muss auch ein bestimmter Typ (Igrouping) vorliegen. Folgender VB.NET Code fällt in die Kategorie geklaut.
Public Class GroupInfo(Of TKey, TItem) 'interface required to show grouped data
Implements IGrouping(Of TKey, TItem)
Private _source As IEnumerable(Of TItem)
Private _key As TKey
'takes a LINQ IGrouping and converts it to a GroupInfo
Public Sub New(key As TKey, source As IEnumerable(Of TItem))
_key = key
_source = source
End Sub
Private Function IEnumerable_GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return _source.GetEnumerator
End Function
Public Function GetEnumerator() As IEnumerator(Of TItem) Implements IEnumerable(Of TItem).GetEnumerator
Return _source.Cast(Of TItem).GetEnumerator()
End Function
Public ReadOnly Property key As TKey Implements IGrouping(Of TKey, TItem).Key
Get
Return _key
End Get
End Property
End Class
Jetzt kann man mit einem LINQ query aus der Liste die passenden Daten, samt Grouping Info zusammenstellen. Anfangsbuchstabe + voriges Objekt (einfach ein string)
Dim q = From p In liste
Group p By key1 = p.Substring(0, 1) Into g = Group
Select New GroupInfo(Of String, String)(key1, g)
Auch der folgende Code ist quasi geklaut. Im Xaml wird eine CollectionViewSource definiert als Datenquelle für Grid und Listview. Diese muss das Attribut Groued aktiviert haben.
<UserControl.Resources>
<CollectionViewSource x:Name="cvs1" IsSourceGrouped="true" />
</UserControl.Resources>
Wieder im VB.NET Source Code, fehlen noch zwei Zeilen. Die Linq Query wird als DatenQuelle zugewiesen.
cvs1.Source = q
ZoomOut1.ItemsSource = cvs1.View.CollectionGroups
Die Zweite Zeile Programmcode verweist auf den Zoomout Part des Semantic Zoom Controls. Kurz gesagt, es gibt ja zwei Sichten, die normale und die komprimierte/gruppierte.
Alle Beispiele zeigen eine Zuweisung per Code und nicht per Deklaration, was auch denkbar wäre. Der leere Steuerelement zeigt das Konzept recht gut. ZoomIn ist die normale Ansicht.
<SemanticZoom HorizontalAlignment="Left" Margin="278,45,0,0" VerticalAlignment="Top">
<SemanticZoom.ZoomedInView>
<GridView/>
</SemanticZoom.ZoomedInView>
<SemanticZoom.ZoomedOutView>
<ListView/>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
Wesentlich ist,das nun die CollectionViewsource an das ItemSource Attribut gebunden wird, und ein TextBlock für das Bindung erstellt wird. Das es sich hier um ein einfachen String und kein komplexes Objekt handelt ohne Zusatz in den geschweiften Klammern.
<SemanticZoom.ZoomedInView>
<GridView x:Name="grid1" HorizontalAlignment="Left" VerticalAlignment="Top" d:LayoutOverrides="Margin"
ItemsSource="{Binding Source={StaticResource cvs1}}">
<GridView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding }"/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</SemanticZoom.ZoomedInView>
Für den ersten Test ist das ausreichend, wird aber später einer Erweiterung bedürfen.
Eigentlich ganz einfach ist der OutView. da es hier ein Objekt GroupInfo gibt,muss das binding an Group.key erfolgen.
<SemanticZoom.ZoomedOutView>
<GridView Foreground="White" x:Name="ZoomOut1" >
<GridView.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Group.key}"
FontFamily="Segoe UI Light"
FontSize="24"
Foreground="silver" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</SemanticZoom.ZoomedOutView>
Was hier so locker lässig aussieht, hat mich Stunden gekostet. Schon der kleinste Fehler und man erhält kein Ergebnis und meist auch keine Fehlermeldung, Das debuggen von XAML klapp bei mir nicht (Consumer Preview von Windows 8).
Und die Semantische vergrößerte Ansicht.
Wenn man nun auf Q klickt, kommt man zwar in die ursprüngliche Sicht zurück, landet aber bei A und nicht bei Q.
Es muss noch die Verbindungzwischen den zwei Views hergestellt werden. Dafür braucht das Gridview eine Gruppierung auf den Wert (Key) des Zoomoutviews.
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text='{Binding Key}' Foreground="Gray" Margin="5" FontSize="18" FontFamily="Segoe UI Light" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="GroupItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupItem">
<StackPanel Orientation="Vertical">
<ContentPresenter Content="{TemplateBinding Content}" />
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding GroupItems}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" MaximumRowsOrColumns="10" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
Der Windows 8 METRO APP Prototyp funktioniert. Das Ergebnis enttäuscht aber in Bezug auf Performance. Der Wechsel zwischen den Views dauert mehrere Sekunden. Die Dokumentation ist unzureichend und das XAML METRO VB.NET und C# Beispiel funktioniert nicht komplett. Die Fehlersuche wird durch Visual Studio 11 nicht ausreichend unterstützt. Im Vergleich zu Silverlight und WPF ist erheblich mehr Aufwand nötig. Ich werde versuchen, den Use Case zu optimieren.