Windows Phone Silverlight zu UWP-Fallstudie: Bookstore2

Diese Fallstudie , die auf den Informationen in Bookstore1 basiert, beginnt mit einer Windows Phone Silverlight-App, die gruppierte Daten in einem LongListSelector anzeigt. Im Ansichtsmodell stellt jede Instanz der Klasse Author die Gruppe der Bücher dar, die von diesem Autor geschrieben wurden, und im LongListSelector können wir entweder die Liste der Bücher nach Autor gruppiert anzeigen, oder wir können verkleinern, um eine Sprungliste von Autoren anzuzeigen. Die Sprungliste ermöglicht eine wesentlich schnellere Navigation im Vergleich zum Blättern in der Bücherliste. Wir gehen durch die Schritte zum Portieren der App zu einer Windows 10-Universelle Windows-Plattform (UWP)-App.

Hinweis : Wenn beim Öffnen von Bookstore2Universal_10 in Visual Studio die Meldung "Visual Studio-Update erforderlich" angezeigt wird, führen Sie die Schritte zum Festlegen der Zielplattformversion in TargetPlatformVersion aus.

Downloads

Laden Sie die Bookstore2WPSL8-Windows Phone Silverlight-App herunter.

Laden Sie die Bookstore2Universal_10 Windows 10-App herunter.

Die Windows Phone Silverlight-App

Die folgende Abbildung zeigt, wie Bookstore2WPSL8 – die App, die wir portieren möchten – aussieht. Es ist ein vertikal scrollendes LongListSelector von Büchern, die nach Autor gruppiert sind. Sie können die Sprungliste verkleineren, und von dort aus können Sie wieder zu einer beliebigen Gruppe navigieren. Für diese App gibt es zwei Hauptelemente: das Ansichtsmodell, das die gruppierte Datenquelle bereitstellt, und die Benutzeroberfläche, die an dieses Ansichtsmodell gebunden wird. Wie wir sehen, portieren beide Teile problemlos von Windows Phone Silverlight-Technologie zur Universelle Windows-Plattform (UWP).

Wie bookstore2wpsl8 aussieht

Portieren zu einem Windows 10-Projekt

Es ist eine schnelle Aufgabe, ein neues Projekt in Visual Studio zu erstellen, Dateien aus Bookstore2WPSL8 zu kopieren und die kopierten Dateien in das neue Projekt einzuschließen. Erstellen Sie zunächst ein neues Projekt für leere Anwendungen (Universelle Windows-Anwendung). Benennen Sie ihn Bookstore2Universal_10. Dies sind die Dateien, die von Bookstore2WPSL8 in Bookstore2Universal_10 kopiert werden sollen.

  • Kopieren Sie den Ordner mit den PNG-Dateien für das Bucheinbandbild (der Ordner lautet \Assets\CoverImages). Stellen Sie nach dem Kopieren des Ordners in Projektmappen-Explorer sicher, dass "Alle Dateien anzeigen" aktiviert ist. Klicken Sie mit der rechten Maustaste auf den Ordner, den Sie kopiert haben, und klicken Sie auf "In Project einschließen". Dieser Befehl bedeutet, dass wir Dateien oder Ordner in einem Projekt "einschließen". Klicken Sie jedes Mal, wenn Sie eine Datei oder einen Ordner kopieren, in Projektmappen-Explorer auf "Aktualisieren", und fügen Sie dann die Datei oder den Ordner in das Projekt ein. Dies ist für Dateien, die Sie im Ziel ersetzen, nicht erforderlich.
  • Kopieren Sie den Ordner, der die Quelldatei des Ansichtsmodells enthält (der Ordner ist \ViewModel).
  • Kopieren Sie "MainPage.xaml", und ersetzen Sie die Datei im Ziel.

Wir können die App.xaml beibehalten und App.xaml.cs, die Visual Studio für uns im Windows 10-Projekt generiert hat.

Bearbeiten Sie den Quellcode und die Markupdateien, die Sie soeben kopiert haben, und ändern Sie alle Verweise auf den Bookstore2WPSL8-Namespace in Bookstore2Universal_10. Eine schnelle Möglichkeit besteht darin, das Feature "In Dateien ersetzen" zu verwenden. Im imperativen Code in der Ansichtsmodellquelldatei sind diese Portierungsänderungen erforderlich.

  • Wechseln Sie System.ComponentModel.DesignerProperties zu DesignMode diesem Befehl, und verwenden Sie dann den Befehl "Auflösen ". Löschen Sie die IsInDesignTool Eigenschaft, und verwenden Sie IntelliSense, um den richtigen Eigenschaftsnamen hinzuzufügen: DesignModeEnabled.
  • Verwenden Sie den Befehl "Auflösen" auf ImageSource.
  • Verwenden Sie den Befehl "Auflösen" auf BitmapImage.
  • Löschen using System.Windows.Media; und using System.Windows.Media.Imaging;.
  • Ändern Sie den von der eigenschaft Bookstore2Universal_10.BookstoreViewModel.AppName zurückgegebenen Wert von "BOOKSTORE2WPSL8" in "BOOKSTORE2UNIVERSAL".
  • Genau wie bei Bookstore1 aktualisieren Sie die Implementierung der BookSku.CoverImage-Eigenschaft (siehe Binden eines Bilds an ein Ansichtsmodell).

In "MainPage.xaml" sind diese anfänglichen Portierungsänderungen erforderlich.

Ersetzen des LongListSelector

Durch das Ersetzen des LongListSelector durch ein SemanticZoom-Steuerelement werden mehrere Schritte ausgeführt, also beginnen wir damit. Ein LongListSelector bindet direkt an die gruppierte Datenquelle, aber ein SemanticZoom enthält ListView- oder GridView-Steuerelemente, die indirekt über einen CollectionViewSource-Adapter an die Daten gebunden werden. Die CollectionViewSource muss im Markup als Ressource vorhanden sein. Beginnen wir also damit, dies dem Markup in "MainPage.xaml" hinzuzufügen <Page.Resources>.

    <CollectionViewSource
        x:Name="AuthorHasACollectionOfBookSku"
        Source="{Binding Authors}"
        IsSourceGrouped="true"/>

Beachten Sie, dass die Bindung für LongListSelector.ItemsSource zum Wert von CollectionViewSource.Source wird, und LongListSelector.IsGroupingEnabled wird CollectionViewSource.IsSourceGrouped. Die CollectionViewSource hat einen Namen (Hinweis: kein Schlüssel, wie Sie erwarten), damit wir eine Bindung daran herstellen können.

Ersetzen Sie als Nächstes das phone:LongListSelector Markup durch dieses Markup, das uns einen vorläufigen SemanticZoom für die Arbeit mitgibt.

    <SemanticZoom>
        <SemanticZoom.ZoomedInView>
            <ListView
                ItemsSource="{Binding Source={StaticResource AuthorHasACollectionOfBookSku}}"
                ItemTemplate="{StaticResource BookTemplate}">
                <ListView.GroupStyle>
                    <GroupStyle
                        HeaderTemplate="{StaticResource AuthorGroupHeaderTemplate}"
                        HidesIfEmpty="True"/>
                </ListView.GroupStyle>
            </ListView>
        </SemanticZoom.ZoomedInView>
        <SemanticZoom.ZoomedOutView>
            <ListView
                ItemsSource="{Binding CollectionGroups, Source={StaticResource AuthorHasACollectionOfBookSku}}"
                ItemTemplate="{StaticResource ZoomedOutAuthorTemplate}"/>
        </SemanticZoom.ZoomedOutView>
    </SemanticZoom>

Der LongListSelector-Begriff der Flachlisten- und Sprunglistenmodi wird im SemanticZoom-Konzept einer verkleinerten ansicht bzw. einer verkleinerten Ansicht beantwortet. Die vergrößerte Ansicht ist eine Eigenschaft, und Sie legen diese Eigenschaft auf eine Instanz eines ListView-Steuerelements fest. In diesem Fall ist die verkleinerte Ansicht auch auf eine ListView festgelegt, und beide ListView-Steuerelemente sind an unsere CollectionViewSource gebunden. Die vergrößerte Ansicht verwendet dieselbe Elementvorlage, Gruppenkopfvorlage und HideEmptyGroups-Einstellung (jetzt "HidesIfEmpty") wie die flache Liste von LongListSelector. Und die verkleinerte Ansicht verwendet eine Elementvorlage sehr ähnlich wie die im Sprunglistenstil von LongListSelector (AuthorNameJumpListStyle). Beachten Sie außerdem, dass die verkleinerte Ansicht an eine spezielle Eigenschaft der CollectionViewSource namens CollectionGroups gebunden ist, bei der es sich um eine Auflistung handelt, die die Gruppen und nicht die Elemente enthält.

Wir brauchen AuthorNameJumpListStylenicht mehr , zumindest nicht alle davon. Wir benötigen nur die Datenvorlage für die Gruppen (die Autoren in dieser App sind) in der verkleinerten Ansicht. Daher löschen wir die AuthorNameJumpListStyle Formatvorlage und ersetzen sie durch diese Datenvorlage.

   <DataTemplate x:Key="ZoomedOutAuthorTemplate">
        <Border Margin="9.6,0.8" Background="{Binding Converter={StaticResource JumpListItemBackgroundConverter}}">
            <TextBlock Margin="9.6,0,9.6,4.8" Text="{Binding Group.Name}" Style="{StaticResource SubtitleTextBlockStyle}"
            Foreground="{Binding Converter={StaticResource JumpListItemForegroundConverter}}" VerticalAlignment="Bottom"/>
        </Border>
    </DataTemplate>

Beachten Sie, dass es sich bei dem Datenkontext dieser Datenvorlage nicht um eine Gruppe handelt, sondern um eine Bindung an eine spezielle Eigenschaft namens "Group".

Sie können die App jetzt erstellen und ausführen. So sieht es im mobilen Emulator aus.

die UWP-App auf Mobilgeräten mit Änderungen am ursprünglichen Quellcode

Das Ansichtsmodell und die vergrößerten und verkleinerten Ansichten arbeiten ordnungsgemäß zusammen, obwohl ein Problem darin besteht, dass wir etwas mehr Formatierung und Vorlagen bearbeiten müssen. Beispielsweise werden die richtigen Formatvorlagen und Pinsel noch nicht verwendet, sodass der Text in den Gruppenkopfzeilen nicht sichtbar ist, auf die Sie klicken können, um zu verkleinern. Wenn Sie die App auf einem Desktopgerät ausführen, wird ein zweites Problem angezeigt. Dies bedeutet, dass die App die Benutzeroberfläche noch nicht anpasst, um die optimale Benutzererfahrung und die Nutzung von Speicherplatz auf größeren Geräten zu ermöglichen, bei denen Fenster potenziell viel größer als der Bildschirm eines mobilen Geräts sein können. In den nächsten Abschnitten (anfängliches Formatieren und Vorlagen, adaptive UI und endgültige Formatierung) werden diese Probleme behoben.

Anfängliches Formatieren und Vorlagen

Wenn Sie die Gruppenkopfzeilen schön ausräumen möchten, bearbeiten AuthorGroupHeaderTemplate Sie den Rand "0,0,0,9.6" des Rahmens, und legen Sie diesen fest.

Wenn Sie die Buchelemente schön ausräumen möchten, bearbeiten BookTemplate Sie den Rand, und legen Sie den Rand "9.6,0" auf beide TextBlock-Elementefest.

Um den App-Namen und den Seitentitel etwas besser zu gestalten, entfernen Sie innen TitlePanelden oberen Rand des zweiten TextBlock , indem Sie den Wert auf "7.2,0,0,0"festlegen. TitlePanel Und auf sich selbst legen Sie den Rand auf 0 (oder welchen Wert Ihnen gut aussieht)

Ändern LayoutRootdes Hintergrunds in "{ThemeResource ApplicationPageBackgroundThemeBrush}".

Adaptive UI

Da wir mit einer Smartphone-App begonnen haben, überrascht es nicht, dass das UI-Layout unserer portierten App wirklich nur für kleine Geräte und schmale Fenster in dieser Phase im Prozess sinnvoll ist. Wir möchten jedoch, dass das UI-Layout sich selbst anpasst und den Platz besser nutzt, wenn die App in einem breiten Fenster ausgeführt wird (was nur auf einem Gerät mit einem großen Bildschirm möglich ist), und nur für die Verwendung der UI, die wir derzeit haben, wenn das Fenster der App schmal ist (was auf einem kleinen Gerät geschieht, und kann auch auf einem großen Gerät geschehen).

Wir können das adaptive Visual State Manager-Feature verwenden, um dies zu erreichen. Wir legen Eigenschaften für visuelle Elemente fest, sodass die Benutzeroberfläche standardmäßig im schmalen Zustand mit den Vorlagen angeordnet wird, die wir derzeit verwenden. Anschließend erkennen wir, wann das Fenster der App breiter als oder gleich einer bestimmten Größe ist (gemessen in Einheiten effektiver Pixel), und als Reaktion ändern wir die Eigenschaften visueller Elemente so, dass wir ein größeres und breiteres Layout erhalten. Wir setzen diese Eigenschaftsänderungen in einen visuellen Zustand ein, und wir verwenden einen adaptiven Trigger, um kontinuierlich zu überwachen und zu bestimmen, ob dieser visuelle Zustand angewendet werden soll, oder nicht, abhängig von der Breite des Fensters in effektiven Pixeln. In diesem Fall wird die Fensterbreite ausgelöst, aber es ist auch möglich, die Fensterhöhe auszulösen.

Für diesen Anwendungsfall ist eine mindeste Fensterbreite von 548 Epx geeignet, da dies die Größe des kleinsten Geräts ist, auf dem das breite Layout angezeigt werden soll. Smartphones sind in der Regel kleiner als 548 Epx, also auf einem kleinen Gerät wie diesem, wir bleiben im schmalen Standardlayout. Auf einem PC wird das Fenster standardmäßig breit genug gestartet, um den Schalter in den breiten Zustand auszulösen, der 250 x 250 Elemente anzeigt. Von dort aus können Sie das Fenster schmal genug ziehen, um mindestens zwei Spalten der 250 x 250 Elemente anzuzeigen. Jeder schmalere als das und der Trigger wird deaktiviert, der breite visuelle Zustand wird entfernt, und das schmale Standardlayout wird wirksam.

Bevor wir den adaptiven Visual State Manager-Teil angehen, müssen wir zuerst den breiten Zustand entwerfen, und das bedeutet, dass einige neue visuelle Elemente und Vorlagen zu unserem Markup hinzugefügt werden. In diesen Schritten wird beschrieben, wie dies zu tun ist. Mithilfe von Benennungskonventionen für visuelle Elemente und Vorlagen fügen wir das Wort "breit" in den Namen eines elements oder einer Vorlage ein, das sich für den breiten Zustand befindet. Wenn ein Element oder eine Vorlage nicht das Wort "wide" enthält, können Sie davon ausgehen, dass es sich um den schmalen Zustand handelt, der den Standardzustand und dessen Eigenschaftswerte als lokale Werte für visuelle Elemente auf der Seite festgelegt werden. Nur die Eigenschaftswerte für den breiten Zustand werden über einen tatsächlichen visuellen Zustand im Markup festgelegt.

  • Erstellen Sie eine Kopie des SemanticZoom-Steuerelements im Markup, und legen Sie sie für die Kopie fest x:Name="narrowSeZo" . Legen Sie im Original fest x:Name="wideSeZo" , und legen Sie sie auch so fest Visibility="Collapsed" , dass das breite Element standardmäßig nicht sichtbar ist.
  • wideSeZoÄndern Sie in "ListViews" in "GridViews" sowohl in der vergrößerten Ansicht als auch in der verkleinerten Ansicht.
  • Erstellen Sie eine Kopie dieser drei Ressourcen AuthorGroupHeaderTemplate, ZoomedOutAuthorTemplateund BookTemplate fügen Sie das Wort Wide an die Schlüssel der Kopien an. Aktualisieren Sie wideSeZo außerdem, damit sie auf die Schlüssel dieser neuen Ressourcen verweist.
  • Ersetzen Sie den Inhalt von AuthorGroupHeaderTemplateWide durch <TextBlock Style="{StaticResource SubheaderTextBlockStyle}" Text="{Binding Name}"/>.
  • Ersetzen Sie den Inhalt von ZoomedOutAuthorTemplateWide durch Folgendes:
    <Grid HorizontalAlignment="Left" Width="250" Height="250" >
        <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}"/>
        <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
          <TextBlock Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}"
              Style="{StaticResource SubtitleTextBlockStyle}"
            Height="80" Margin="15,0" Text="{Binding Group.Name}"/>
        </StackPanel>
    </Grid>
  • Ersetzen Sie den Inhalt von BookTemplateWide durch Folgendes:
    <Grid HorizontalAlignment="Left" Width="250" Height="250">
        <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}"/>
        <Image Source="{Binding CoverImage}" Stretch="UniformToFill"/>
        <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
            <TextBlock Style="{StaticResource SubtitleTextBlockStyle}"
                Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}"
                TextWrapping="NoWrap" TextTrimming="CharacterEllipsis"
                Margin="12,0,24,0" Text="{Binding Title}"/>
            <TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="{Binding Author.Name}"
                Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" TextWrapping="NoWrap"
                TextTrimming="CharacterEllipsis" Margin="12,0,12,12"/>
        </StackPanel>
    </Grid>
  • Für den breiten Zustand benötigen die Gruppen in der vergrößerten Ansicht mehr vertikalen Atemraum um sie herum. Das Erstellen und Verweisen auf eine Elementpanelvorlage gibt uns die gewünschten Ergebnisse. So sieht das Markup aus.
   <ItemsPanelTemplate x:Key="ZoomedInItemsPanelTemplate">
        <ItemsWrapGrid Orientation="Horizontal" GroupPadding="0,0,0,20"/>
    </ItemsPanelTemplate>
    ...

    <SemanticZoom x:Name="wideSeZo" ... >
        <SemanticZoom.ZoomedInView>
            <GridView
            ...
            ItemsPanel="{StaticResource ZoomedInItemsPanelTemplate}">
            ...
  • Fügen Sie schließlich das entsprechende Visual State Manager-Markup als erstes untergeordnetes Element von LayoutRoot.
    <Grid x:Name="LayoutRoot" ... >
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState x:Name="WideState">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="548"/>
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="wideSeZo.Visibility" Value="Visible"/>
                        <Setter Target="narrowSeZo.Visibility" Value="Collapsed"/>
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

    ...

Endgültige Formatierung

Alles, was noch bleibt, sind einige endgültige Formatierungsoptimierungen.

  • Legen AuthorGroupHeaderTemplateSie Foreground="White" in " TextBlock " fest, damit sie bei der Ausführung auf der Mobilgerätefamilie korrekt aussieht.
  • Zum FontWeight="SemiBold" TextBlock in beiden AuthorGroupHeaderTemplate und ZoomedOutAuthorTemplate.
  • In narrowSeZo, die Gruppenkopfzeilen und die Autoren in der verkleinerten Ansicht sind linksbündig ausgerichtet, anstatt gestreckt zu werden, also arbeiten wir daran. Wir erstellen einen HeaderContainerStyle für die vergrößerte Ansicht, wobei "HorizontalContentAlignment" auf "StretchHorizontalContentAlignment" festgelegt ist. Außerdem erstellen wir einen ItemContainerStyle für die verkleinerte Ansicht, die denselben Setter enthält. Das sieht so aus:
   <Style x:Key="AuthorGroupHeaderContainerStyle" TargetType="ListViewHeaderItem">
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    </Style>

    <Style x:Key="ZoomedOutAuthorItemContainerStyle" TargetType="ListViewItem">
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    </Style>

    ...

    <SemanticZoom x:Name="narrowSeZo" ... >
        <SemanticZoom.ZoomedInView>
            <ListView
            ...
                <ListView.GroupStyle>
                    <GroupStyle
                    ...
                    HeaderContainerStyle="{StaticResource AuthorGroupHeaderContainerStyle}"
                    ...
        <SemanticZoom.ZoomedOutView>
            <ListView
                ...
                ItemContainerStyle="{StaticResource ZoomedOutAuthorItemContainerStyle}"
                ...

Diese letzte Sequenz von Formatierungsvorgängen lässt die App wie folgt aussehen.

die portierte Windows 10-App, die auf einem Desktopgerät ausgeführt wird, vergrößerte Ansicht, zwei Fenstergrößen

Die portierte Windows 10-App, die auf einem Desktopgerät ausgeführt wird, vergrößerte Ansicht, zwei Fenstergrößen die portierte Windows 10-App auf einem Desktopgerät, verkleinerte Ansicht, zwei Fenstergrößen

Die portierte Windows 10-App auf einem Desktopgerät, verkleinerte Ansicht, zwei Fenstergrößen

die portierte Windows 10-App, die auf einem mobilen Gerät ausgeführt wird, vergrößerte Ansicht

Die portierte Windows 10-App, die auf einem mobilen Gerät ausgeführt wird, vergrößerte Ansicht

die portierte Windows 10-App auf einem mobilen Gerät, verkleinerte Ansicht

Die portierte Windows 10-App auf einem mobilen Gerät, verkleinerte Ansicht

Flexibleres Anzeigenmodell

Dieser Abschnitt enthält ein Beispiel für Einrichtungen, die uns durch Verschieben unserer App zur Verwendung der UWP offenstehen. Hier erläutern wir optionale Schritte, die Sie ausführen können, um ihr Ansichtsmodell flexibler zu gestalten, wenn über eine CollectionViewSource zugegriffen wird. Das Ansichtsmodell (die Quelldatei befindet sich in ViewModel\BookstoreViewModel.cs), das wir aus der Windows Phone Silverlight-App Bookstore2WPSL8 portiert haben, enthält eine Klasse namens Author, die von List<T> abgeleitet ist, wobei T BookSku ist. Das bedeutet, dass die Author-Klasse eine Gruppe von BookSku ist.

Wenn wir CollectionViewSource.Source an Autoren binden, besteht die einzige Kommunikation darin, dass jeder Autor in Autoren eine Gruppe von Etwas ist. Wir überlassen es der CollectionViewSource , um zu bestimmen, dass Author in diesem Fall eine Gruppe von BookSku ist. Das funktioniert: Aber es ist nicht flexibel. Was geschieht, wenn "Author" sowohl eine Gruppe von "BookSku" als auch eine Gruppe der Adressen sein soll, in denen der Autor gelebt hat? Der Autor kann nicht beide Gruppen sein . "Autor" kann jedoch eine beliebige Anzahl von Gruppen haben . Und das ist die Lösung: Verwenden Sie das has-a-group-Muster anstelle oder zusätzlich zu dem Muster "is-a-group ", das wir derzeit verwenden. Gehen Sie dazu wie folgt vor:

  • Ändern Sie "Author", sodass sie nicht mehr von List<T> abgeleitet wird.
  • Dieses Feld hinzufügen zu
  • Diese Eigenschaft hinzufügen zu
  • Und natürlich können wir die obigen beiden Schritte wiederholen, um beliebig viele Gruppen zu "Autor" hinzuzufügen.
  • Ändern Sie die Implementierung der AddBookSku-Methode in this.BookSkus.Add(bookSku);.
  • Nachdem Author über mindestens eine Gruppe verfügt, müssen wir mit der CollectionViewSource kommunizieren, welche dieser Gruppen verwendet werden sollen. Fügen Sie dazu diese Eigenschaft der CollectionViewSource hinzu: ItemsPath="BookSkus"

Diese Änderungen lassen diese App funktionell unverändert, aber Sie wissen jetzt, wie Sie Author und die CollectionViewSource erweitern können, sollten Sie dies benötigen. Nehmen wir eine letzte Änderung an "Author" vor, sodass bei Verwendung ohne Angabe von CollectionViewSource.ItemsPath eine Standardgruppe unserer Wahl verwendet wird:

    public class Author : IEnumerable<BookSku>
    {
        ...

        public IEnumerator<BookSku> GetEnumerator()
        {
            return this.BookSkus.GetEnumerator();
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.BookSkus.GetEnumerator();
        }
    }

Und jetzt können wir auswählen, ItemsPath="BookSkus" ob wir möchten, und die App verhält sich weiterhin auf die gleiche Weise.

Zusammenfassung

Bei dieser Fallstudie handelte es sich um eine ehrgeizigere Benutzeroberfläche als die vorherige. Alle Einrichtungen und Konzepte der Windows Phone Silverlight LongListSelector – und vieles mehr – wurden als UWP-App in Form von SemanticZoom, ListView, GridView und CollectionViewSource zur Verfügung gestellt. Wir haben gezeigt, wie Sie imperativen Code und Markup in einer UWP-App wiederverwenden oder kopieren und bearbeiten können, um Funktionen, UI und Interaktionen zu erzielen, die auf die schmalsten und breitesten Formfaktoren von Windows-Geräten und alle Größen dazwischen zugeschnitten sind.