ItemsRepeater

Verwenden Sie ein ItemsRepeater-Steuerelement, um benutzerdefinierte Sammlungsoberflächen mit einem flexiblen Layoutsystem, benutzerdefinierten Ansichten und Virtualisierung zu erstellen.

Im Gegensatz zu ListView stellt ItemsRepeater keine umfassende Benutzeroberfläche bereit– „ItemsRepeater“ hat keine Standardbenutzeroberfläche und stellt keine Richtlinien hinsichtlich Fokus, Auswahl, oder Benutzerinteraktion bereit. Stattdessen ist das Steuerelement ein Baustein, den du dazu verwenden kannst, deine eigenen einzigartigen sammlungsbasierten Oberflächen und benutzerdefinierten Steuerelemente zu erstellen. Weil es keine integrierte Richtlinien hat, können Sie Richtlinien zuordnen, um die von Ihnen geforderte Benutzeroberfläche zu erstellen. Beispielsweise können Sie das zu verwendende Layout, die Tastaturunterstützungsrichtlinie, die Auswahlrichtlinie usw. definieren.

Vom Konzept her können Sie sich ItemsRepeater als einen datengesteuerten Bereich statt als ein vollständiges Steuerelement wie „ListView“ vorstellen. Sie geben eine Sammlung von anzuzeigenden Datenelementen, eine Elementvorlage, über die ein Benutzeroberflächenelement für jedes Datenelement generiert wird, und ein Layout an, das die Größe und die Position der Elemente bestimmt. „ItemsRepeater“ erstellt dann anhand der Datenquelle untergeordnete Elemente und zeigt diese entsprechend der Elementvorlage und dem Layout an. Die angezeigten Elemente müssen nicht homogen sein, da „ItemsRepeater“ Inhalte, die den Datenelementen entsprechen, anhand von Kriterien laden kann, die Sie in einer Datenvorlagenauswahl angeben.

Ist dies das richtige Steuerelement?

Verwenden Sie ein ItemsRepeater-Steuerelement, um eine benutzerdefinierte Anzeige für eine Sammlung von Daten zu erstellen. Obwohl es verwendet werden kann, einen einfachen Satz von Elementen darzustellen, werden Sie es häufig wahrscheinlich als das Anzeigeelement in der Vorlage eines benutzerdefinierten Steuerelements verwenden.

Wenn Sie ein sofort einsatzbereites Steuerelement benötigen, um bei minimaler Anpassung Daten in einer Liste oder einem Raster anzuzeigen, sollten Sie ein ListView- oder GridView-Steuerelement verwenden.

„ItemsRepeater“ hat keine integrierte Sammlung für Elemente (Items-Sammlung). Wenn Sie statt einer Bindung an eine separate Datenquelle direkt eine Items-Sammlung bereitstellen müssen, benötigen Sie wahrscheinlich eine Oberfläche mit eingeschränkterer Richtlinie und sollten ListView oder GridView verwenden.

Sowohl ItemsControl als auch „ItemsRepeater“ ermöglichen anpassbare Sammlungsoberflächen, aber im Gegensatz zu „ItemsControl“ unterstützt „ItemsRepeater“ das Virtualisieren von Benutzeroberflächenlayouts. Es empfiehlt sich, „ItemsRepeater“ statt „ItemsControl“ zu verwenden, egal, ob nur einige Datenelemente dargestellt werden sollen oder ob ein benutzerdefiniertes Sammlungssteuerelement erstellt werden soll.

UWP und WinUI 2

Wichtig

Die Informationen und Beispiele in diesem Artikel sind für Apps optimiert, die das Windows App SDK und WinUI 3 verwenden, gelten jedoch allgemein für UWP-Apps, die WinUI 2 verwenden. In der UWP-API-Referenz finden Sie plattformspezifische Informationen und Beispiele.

Dieser Abschnitt enthält Informationen, die Sie zum Verwenden des Steuerelements in einer UWP- oder WinUI 2-App benötigen.

Für ItemsRepeater für UWP-Apps ist die Windows-UI-Bibliothek 2 erforderlich. Weitere Informationen, einschließlich Installationsanweisungen, finden Sie unter Windows UI Library (Windows-UI-Bibliothek). APIs für dieses Steuerelement sind im Microsoft.UI.Xaml.Controls-Namespace vorhanden.

Zur Verwendung des Codes in diesem Artikel mit WinUI 2 stellen Sie die in Ihrem Projekt enthaltenen Windows-UI-Bibliothek-APIs mithilfe eines Alias in XAML dar (wir verwenden muxc). Weitere Informationen finden Sie unter Erste Schritte mit WinUI 2.

xmlns:muxc="using:Microsoft.UI.Xaml.Controls"

<muxc:ItemsRepeater />

Scrollen mit „ItemsRepeater“

ItemsRepeater ist nicht aus Control abgeleitet und hat somit keine Steuerelementvorlage. Aus diesem Grund enthält „ItemsRepeater“ kein integriertes Scrollen, wie dies für „ListView“ oder andere Sammlungssteuerelemente der Fall ist.

Wenn Sie ein ItemsRepeater-Steuerelement verwenden, sollten Sie Scrollfunktionalität bereitstellen, indem Sie es in ein ScrollViewer-Steuerelement einbinden.

Hinweis

Wird Ihre App unter früheren Versionen von Windows ausgeführt – Versionen, die vor Windows 10, Version 1809, veröffentlicht wurden –, müssen Sie das ScrollViewer-Steuerelement im ItemsRepeaterScrollHost-Steuerelement hosten.

<muxc:ItemsRepeaterScrollHost>
    <ScrollViewer>
        <muxc:ItemsRepeater ... />
    </ScrollViewer>
</muxc:ItemsRepeaterScrollHost>

Wird Ihre App nur unter Windows 10 ab Version 1809 ausgeführt, besteht keine Notwendigkeit, ItemsRepeaterScrollHost zu verwenden.

Vor Windows 10, Version 1809, ist in ScrollViewer die Schnittstelle IScrollAnchorProvider nicht implementiert, die für ItemsRepeater benötigt wird. Das ItemsRepeaterScrollHost-Steuerelement ermöglicht das Koordinieren von ItemsRepeater und ScrollViewer unter früheren Versionen, um die sichtbaren Positionen von Elementen, die der Benutzer anzeigt, ordnungsgemäß beizubehalten. Andernfalls kann es passieren, dass die Elemente verschoben werden oder plötzlich verschwinden, wenn die Elemente in der Liste geändert werden oder wenn die Größe der App geändert wird.

Erstellen eines „ItemsRepeater“-Steuerelements

Die WinUI 3-Katalog-App umfasst interaktive Beispiele für die meisten WinUI 3-Steuerelemente, -Features und -Funktionen. Laden Sie die App aus dem Microsoft Store herunter, oder rufen Sie den Quellcode auf GitHub ab.

Um ein ItemsRepeater-Steuerelement verwenden zu können, müssen ihm die anzuzeigenden Daten zuordnen, indem Sie die ItemsSource-Eigenschaft festlegen. Danach teilen Sie ihm mit, wie die Elemente angezeigt werden sollen, indem Sie die ItemTemplate-Eigenschaft festlegen.

ItemsSource

Um die Ansicht aufzufüllen, legen Sie die ItemsSource-Eigenschaft auf eine Sammlung von Datenelementen fest. Hier wird die ItemsSource-Eigenschaft im Code direkt auf eine Instanz einer Sammlung festgelegt.

ObservableCollection<string> Items = new ObservableCollection<string>();

ItemsRepeater itemsRepeater1 = new ItemsRepeater();
itemsRepeater1.ItemsSource = Items;

Sie können die ItemsSource-Eigenschaft auch an eine Sammlung in XAML binden. Weitere Informationen zur Datenbindung finden Sie unter Übersicht über Datenbindung.

<ItemsRepeater ItemsSource="{x:Bind Items}"/>

ItemTemplate

Um anzugeben, wie ein Datenelement visualisiert wird, legen Sie die ItemTemplate-Eigenschaft auf eine DataTemplate- oder DataTemplateSelector-Instanz fest, die Sie definiert haben. Die Datenvorlage definiert, wie die Daten visualisiert werden. Standardmäßig wird das Element in der Ansicht mit einer TextBlock-Instanz angezeigt, für die die Zeichenfolgendarstellung des Datenobjekts verwendet wird.

In der Regel möchten Sie jedoch eine ansprechendere Darstellung Ihrer Daten anzeigen, indem Sie eine Vorlage verwenden, in der das Layout und das Aussehen der Steuerelemente definiert sind, in denen Sie ein einzelnes Elements anzeigen. Die Steuerelemente, die Sie in der Vorlage verwenden, können an die Eigenschaften eines Datenobjekts gebunden sein oder statischen Inhalt haben, der intern definiert ist.

DataTemplate

In diesem Beispiel ist das Datenobjekt eine einfache Zeichenfolge. Die DataTemplate-Instanz enthält ein Bild links neben dem Text und legt für die TextBlock-Instanz fest, dass die Zeichenfolge in Blaugrün angezeigt werden soll.

Hinweis

Wenn Sie die x:Bind-Markuperweiterung in DataTemplate verwenden, müssen Sie „DataType“ (x:DataType) für „DataTemplate“ angeben.

<DataTemplate x:DataType="x:String">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="47"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Image Source="Assets/placeholder.png" Width="32" Height="32"
               HorizontalAlignment="Left"/>
        <TextBlock Text="{x:Bind}" Foreground="Teal"
                   FontSize="15" Grid.Column="1"/>
    </Grid>
</DataTemplate>

Nachstehend sind die Elemente so dargestellt, wie sie mit dieser DataTemplate-Instanz angezeigt würden.

Elemente, die mit einer Datenvorlage angezeigt werden

Die Anzahl der Objekte, die in der DataTemplate-Instanz für ein Element verwendet werden, kann einen erheblichen Einfluss auf die Leistung haben, wenn in Ihrer Ansicht sehr viele Elemente angezeigt werden. Weitere Informationen sowie Beispiele zur Verwendung von DataTemplate-Instanzen, um das Aussehen von Elementen in Ihrer Liste zu definieren, finden Sie unter Elementcontainer und Vorlagen.

Tipp

Wenn Sie der Einfachheit halber die Vorlage intern deklarieren möchten, statt dass sie als statische Ressource referenziert wird, können Sie die DataTemplate- oder DataTemplateSelector-Instanz als direktes untergeordnetes Element des ItemsRepeater-Steuerelements angeben. Sie wird als der Wert der ItemTemplate-Eigenschaft zugewiesen. Folgendes ist beispielsweise gültig:

<ItemsRepeater ItemsSource="{x:Bind Items}">
    <DataTemplate>
        <!-- ... -->
    </DataTemplate>
</ItemsRepeater>

Tipp

Im Gegensatz zu ListView und anderen Sammlungssteuerelementen umhüllt ItemsRepeater die Elemente aus einer DataTemplate-Instanz nicht mit einem zusätzlichen Elementcontainer, der Standardrichtlinien enthält, etwa Ränder, Auffüllung, visuelle Auswahlkomponenten oder ein Zeiger über einem visuellen Zustand. Stattdessen präsentiert ItemsRepeater nur den Inhalt, der in der DataTemplate-Instanz definiert ist. Wenn Sie möchten, dass Ihre Elemente genau so aussehen wie ein Listenansichtselement, können Sie explizit einen Container, z. B. ListViewItem, in Ihre Datenvorlage einfügen. ItemsRepeater zeigt die visuellen ListViewItem-Komponenten an, verwendet aber nicht automatisch weitere Funktionalität, etwa Auswahl oder Anzeigen des Multiauswahl-Kontrollkästchen.

Analog können Sie, wenn Ihre Datensammlung eine Sammlung von Steuerelementen ist, z. B. Button (List<Button>), eine ContentPresenter-Instanz in Ihrer DataTemplate-Instanz anordnen, um das Steuerelement anzuzeigen.

DataTemplateSelector

Die Elemente, die Sie in der Ansicht anzeigen, müssen nicht denselben Typ haben. Sie können die ItemTemplate-Eigenschaft mit einer DataTemplateSelector-Instanz bereitstellen, um anhand von Kriterien, die Sie angegeben haben, verschiedene DataTemplate-Instanzen auszuwählen.

In diesem Beispiel wird davon ausgegangen, dass eine DataTemplateSelector-Instanz definiert ist, in der zwischen zwei unterschiedlichen DataTemplate-Instanzen entschieden wird, um ein „Large“- und ein „Small“-Element darzustellen.

<ItemsRepeater ...>
    <ItemsRepeater.ItemTemplate>
        <local:VariableSizeTemplateSelector Large="{StaticResource LargeItemTemplate}" 
                                            Small="{StaticResource SmallItemTemplate}"/>
    </ItemsRepeater.ItemTemplate>
</ItemsRepeater>

Wenn Sie eine DataTemplateSelector-Instanz definieren, die mit ItemsRepeater verwendet werden soll, müssen Sie nur eine Überschreibung für die SelectTemplateCore(Object)-Methode implementieren. Weitere Informationen und Beispiele finden Sie unter DataTemplateSelector.

Hinweis

Eine Alternative zu DataTemplates, um zu verwalten, wie Elemente in komplexeren Szenarien erstellt werden, besteht darin, Ihre eigene IElementFactory zu implementieren, die als ItemTemplate verwendet wird. Sie ist für das Generieren von Inhalt verantwortlich, wenn dieser angefordert wird.

Konfigurieren der Datenquelle

Verwenden Sie die ItemsSource-Eigenschaft, um die Sammlung anzugeben, mit der der Inhalt von Elementen generiert werden soll. Sie können die „ItemsSource“-Eigenschaft auf jeden Typ festlegen, der IEnumerable implementiert. Zusätzliche Sammlungsschnittstellen, die durch Ihre Datenquelle implementiert sind, bestimmen, welche Funktionalität für die „ItemsRepeater“-Instanz verfügbar ist, um mit Ihren Daten zu interagieren.

In dieser Liste sind die verfügbaren Schnittstellen aufgeführt und ist beschrieben, wann die jeweilige Schnittstelle in Betracht kommt.

  • IEnumerable(.NET) / IIterable

    • Kann für kleine statische Datasets verwendet werden.

      Für die Datenquelle muss mindestens die „IEnumerable / IIterable“-Schnittstelle implementiert werden. Ist dies alles, was unterstützt wird, durchläuft das Steuerelement alle Inhalte einmal, um eine Kopie zu erstellen, die es verwenden kann, um über einen Indexwert auf Elemente zuzugreifen.

  • IReadonlyList(.NET) / IVectorView

    • Kann für statische schreibgeschützte Datasets verwendet werden.

      Ermöglicht dem Steuerelement, über den Index auf Elemente zuzugreifen, und vermeidet redundante interne Kopien.

  • IList(.NET) / IVector

    • Kann für statische Datasets verwendet werden.

      Ermöglicht es dem Steuerelement, über den Index auf Elemente zuzugreifen, und vermeidet redundante interne Kopien.

      Warnung: INotifyCollectionChanged muss implementiert sein, damit Änderungen an der Liste oder dem Vektor in die Benutzeroberfläche übernommen werden.

  • INotifyCollectionChanged(.NET)

    • Empfohlen, um Änderungsbenachrichtigungen zu unterstützen.

      Ermöglicht es dem Steuerelement, auf Änderungen in der Datenquelle zu überwachen und diese Änderungen in die Benutzeroberfläche zu übernehmen.

  • IObservableVector

    • Unterstützt Änderungsbenachrichtigung.

      Hiermit wird es dem Steuerelement, wie bei der INotifyCollectionChanged-Schnittstelle, ermöglicht, auf Änderungen in der Datenquelle zu überwachen und zu reagieren.

      Warnung: Windows.Foundation.IObservableVector<T> unterstützt keine Aktion "Verschieben". Dies kann dazu führen, dass die Benutzeroberfläche für ein Element ihren visuellen Zustand verliert. Beispiel: Ein Element, das derzeit ausgewählt ist oder den Fokus hat, verliert den Fokus verliert und ist nicht mehr ausgewählt, wenn das Verschieben durch ein Entfernen (Remove) gefolgt von einem Hinzufügen (Add) erfolgt.

      Platform.Collections.Vector<T> verwendet IObservableVector<T> und hat dieselbe Einschränkung. Muss eine Move-Aktion unterstützt werden, verwenden Sie die INotifyCollectionChanged-Schnittstelle. Die .NET ObservableCollection T-Klasse<> verwendet INotifyCollectionChanged.

  • IKeyIndexMapping

    • Wird verwendet, wenn jedem Element ein eindeutiger Bezeichner (ID) zugeordnet werden kann. Empfohlen, wenn „Reset“ als Aktion für Sammlungsänderungen verwendet wird.

      Ermöglicht es dem Steuerelement, sehr effizient die vorhandene Benutzeroberfläche wiederherstellen zu können, nachdem eine harte Aktion für Zurücksetzen (Reset-Aktion) im Rahmen eines INotifyCollectionChanged- oder IObservableVector-Ereignisses empfangen wurde. Nachdem das Steuerelement eine „Reset“-Aktion empfangen hat, verwendet es die bereitgestellte eindeutige ID, um die aktuellen Daten mit Elementen zu verknüpfen, die es bereits erstellt hat. Ohne die Zuordnung von Schlüssel zu Index müsste das Steuerelement davon ausgehen, dass es die Benutzeroberfläche für die Daten von Grund auf neu erstellen muss.

Die oben aufgeführten Schnittstellen zeigen, mit Ausnahme von „IKeyIndexMapping“, in „ItemsRepeater“ das gleiche Verhalten wie in „ListView“ und „GridView“.

Die folgenden Schnittstellen für eine Elementequelle (ItemsSource) ermöglichen spezielle Funktionalität in „ListView“- und „GridView“-Steuerelementen, wirken sich derzeit aber nicht auf ein „ItemsRepeater“-Steuerelement aus:

Tipp

Wir legen Wert auf Ihre Meinung! Teilen Sie uns Ihre Meinung zu dem GitHub-Projekt der Windows-UI-Bibliothek mit. Erwägen Sie, Ihre Gedanken zu vorhandenen Vorschlägen wie #374 hinzuzufügen: Add incremental loading support for ItemsRepeater (Unterstützung für inkrementelles Laden zu ItemsRepeater hinzufügen).

Ein alternativer Ansatz zum inkrementellen Laden von Daten, während der Benutzer nach oben oder unten scrollt, besteht darin, die Position des Viewports von „ScrollViewer“ zu beobachten und mehr Daten zu laden, wenn sich der Viewport der Erstreckung nähert.

<ScrollViewer ViewChanged="ScrollViewer_ViewChanged">
    <ItemsRepeater ItemsSource="{x:Bind MyItemsSource}" .../>
</ScrollViewer>
private async void ScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
    if (!e.IsIntermediate)
    {
        var scroller = (ScrollViewer)sender;
        var distanceToEnd = scroller.ExtentHeight - (scroller.VerticalOffset + scroller.ViewportHeight);

        // trigger if within 2 viewports of the end
        if (distanceToEnd <= 2.0 * scroller.ViewportHeight
                && MyItemsSource.HasMore && !itemsSource.Busy)
        {
            // show an indeterminate progress UI
            myLoadingIndicator.Visibility = Visibility.Visible;

            await MyItemsSource.LoadMoreItemsAsync(/*DataFetchSize*/);

            loadingIndicator.Visibility = Visibility.Collapsed;
        }
    }
}

Ändern des Layouts von Elementen

Elemente, die von ItemsRepeater angezeigt werden, werden von einem Layout-Objekt angeordnet, das die Größen und Positionierungen seiner untergeordneten Elemente verwaltet. Wird ein „Layout“-Objekt mit einem „ItemsRepeater“-Steuerelement verwendet, ermöglicht es UI-Virtualisierung. Die bereitgestellten Layouts sind StackLayout und UniformGridLayout. Standardmäßig verwendet „ItemsRepeater“ ein „StackLayout“ mit vertikaler Ausrichtung.

StackLayout

StackLayout ordnet Elemente in einer einzelnen Zeile an, die Sie horizontal oder vertikal ausrichten können.

Sie können die Spacing-Eigenschaft festlegen, um den Abstand zwischen Elementen anzupassen. „Spacing“ wird in der Richtung angewendet, die durch die Ausrichtung (Orientation) des Layouts angegeben ist.

Abstand für StackLayout

In diesem Beispiel wird gezeigt, wie die „ItemsRepeater.Layout“-Eigenschaft auf ein Stapellayout (StackLayout) mit horizontaler Ausrichtung und einem jeweiligen Abstand von 8 Pixeln festgelegt wird.

<!-- xmlns:muxc="using:Microsoft.UI.Xaml.Controls" -->
<muxc:ItemsRepeater ItemsSource="{x:Bind Items}" ItemTemplate="{StaticResource MyTemplate}">
    <muxc:ItemsRepeater.Layout>
        <muxc:StackLayout Orientation="Horizontal" Spacing="8"/>
    </muxc:ItemsRepeater.Layout>
</muxc:ItemsRepeater>

UniformGridLayout

UniformGridLayout positioniert Elemente der Reihe nach in einem Umbruchlayout. Elemente werden in Reihenfolge von links nach rechts angeordnet, wenn die Orientation-Eigenschaft auf Horizontal, und von oben nach unten, wenn „Orientation“ auf Vertical festgelegt ist. Jedes Element hat dieselbe Größe.

Einheitliches Rasterlayout

Die Anzahl der Elemente in jeder Zeile eines horizontalen Layouts wird durch die Mindestbreite eines Elements beeinflusst. Die Anzahl der Elemente in jeder Spalte eines vertikalen Layouts wird durch die Mindesthöhe eines Elements beeinflusst.

  • Sie können explizit eine zu verwendende Mindestgröße bereitstellen, indem Sie die Eigenschaften MinItemHeight und MinItemWidth festlegen.
  • Wenn Sie keine Mindestgröße angeben, wird die gemessene Größe des ersten Elements als die Mindestgröße pro Element angenommen.

Sie können für das Layout auch einen Mindestabstand, der zwischen Zeilen und Spalten eingefügt werden soll, angeben, indem Sie die Eigenschaften MinColumnSpacing und MinRowSpacing festlegen.

Einheitliche Größe und einheitlicher Abstand für Raster

Nachdem die Anzahl der Elemente in einer Zeile oder Spalte anhand von Mindestgröße und Mindestabstand des Elements bestimmt wurde, kann nach dem letzten Element in der Zeile oder Spalte ungenutzter Platz vorhanden sein (wie in der vorherigen Abbildung dargestellt). Sie können angeben, ob zusätzlicher Platz ignoriert wird, verwendet wird, um die Größe jedes Elements zu erhöhen, oder verwendet wird, um zusätzlichen Abstand zwischen den Elementen zu erstellen. Dies wird mit den Eigenschaften ItemsStretch und ItemsJustification gesteuert.

Sie können die ItemsStretch-Eigenschaft festlegen, um anzugeben, wie die Elementgröße erhöht werden soll, um den ungenutzten Platz zu füllen.

In dieser Liste sind die verfügbaren Werte aufgeführt. Für die Definitionen wird für Orientation der Wert Horizontal als Standardwert angenommen.

  • None: Zusätzlicher Platz am Ende der Zeile wird nicht verwendet. Dies ist der Standardwert.
  • Fill: Den Elementen wird zusätzliche Breite zugewiesen, um den verfügbaren Platz vollständig zu nutzen (Höhe bei vertikalem Layout).
  • Uniform: Den Elementen wird zusätzliche Breite zugewiesen, um den verfügbaren Platz vollständig zu nutzen, sowie zusätzliche Höhe, um das Seitenverhältnis beizubehalten (Höhe und Breite werden bei vertikaler Anordnung getauscht).

Diese Abbildung zeigen die Auswirkungen der ItemsStretch-Werte in einem horizontalen Layout.

Einheitliches Dehnen von Rasterelementen

Ist ItemsStretch auf None festgelegt, können Sie durch Festlegen der ItemsJustification-Eigenschaft angeben, wie zusätzlicher Platz dazu verwendet werden soll, die Elemente auszurichten.

In dieser Liste sind die verfügbaren Werte aufgeführt. Für die Definitionen wird für Orientation der Wert Horizontal als Standardwert angenommen.

  • Start: Elemente werden am Anfang der Zeile ausgerichtet. Zusätzlicher Platz am Ende der Zeile wird nicht verwendet. Dies ist der Standardwert.
  • Center: Elemente werden in der Mitte der Zeile ausgerichtet. Zusätzlicher Platz wird gleichmäßig auf den Anfang und das Ende der Zeile verteilt.
  • End: Elemente werden am Ende der Zeile ausgerichtet. Zusätzlicher Platz am Anfang der Zeile wird nicht verwendet.
  • SpaceAround: Elemente werden gleichmäßig verteilt. Vor und nach jedem Element wird gleich großer Platz hinzugefügt.
  • SpaceBetween: Elemente werden gleichmäßig verteilt. Zwischen je zwei Elementen wird gleich großer Platz hinzugefügt. Weder am Anfang noch am Ende der Zeile wird Platz hinzugefügt.
  • SpaceEvenly: Elemente werden gleichmäßig verteilt, wobei gleich viel Platz sowohl zwischen je zwei Elementen als auch am Anfang und am Ende der Zeile hinzugefügt wird.

Diese Abbildung zeigt die Auswirkungen der ItemsStretch-Werte in einem vertikalen Layout (angewendet auf Spalten statt auf Zeilen).

Einheitliche Ausrichtung von Rasterlementen

Tipp

Die ItemsStretch-Eigenschaft wirkt sich auf den Bemessen-Schritt eines Layouts aus. Die ItemsJustification-Eigenschaft wirkt sich auf den Anordnen-Schritt eines Layouts aus.

In diesem Beispiel wird veranschaulicht, wie die ItemsRepeater.Layout-Eigenschaft, auf ein einheitliches Rasterlayout (UniformGridLayout) festgelegt wird.

<!-- xmlns:muxc="using:Microsoft.UI.Xaml.Controls" -->
<muxc:ItemsRepeater ItemsSource="{x:Bind Items}"
                    ItemTemplate="{StaticResource MyTemplate}">
    <muxc:ItemsRepeater.Layout>
        <muxc:UniformGridLayout MinItemWidth="200"
                                MinColumnSpacing="28"
                                ItemsJustification="SpaceAround"/>
    </muxc:ItemsRepeater.Layout>
</muxc:ItemsRepeater>

Lebenszyklusereignisse

Wenn Sie Elemente in einem ItemsRepeater-Steuerelement hosten, müssen Sie möglicherweise, wenn ein Element angezeigt oder dessen Anzeige beendet wird, eine Aktion auslösen, etwa Starten eines asynchronen Downloads von bestimmten Inhalten, Verknüpfen des Elements mit einem Mechanismus zum Nachverfolgen der Auswahl oder Beenden einer Hintergrundaufgabe.

In einem virtualisierenden Steuerelement können Sie sich nicht auf Geladen/Entladen-Ereignisse (Loaded/Unloaded) verlassen, weil das Element möglicherweise nicht aus dem visuellen Livebaum entfernt wird, wenn es erneut verwendet wird. Stattdessen werden andere Ereignisse bereitgestellt, um den Lebenszyklus von Elementen zu verwalten. In dieser schematischen Darstellung ist der Lebenszyklus eines Elements in einem „ItemsRepeater“-Steuerelement gezeigt und wird veranschaulicht, wann die zugehörigen Ereignisse ausgelöst werden.

Schematische Darstellung von Lebenszyklusereignissen

  • ElementPrepared tritt jedes Mal auf, wenn ein Element für die Verwendung vorbereitet wird. Dieses Ereignis tritt sowohl für ein neu erstelltes Element als auch für ein Element auf, das bereits vorhanden ist und aus der Wiederverwendungswarteschlange erneut verwendet wird.
  • ElementClearing tritt jedes Mal unmittelbar auf, nachdem ein Element an die Wiederverwendungswarteschlange gesendet wurde, beispielsweise wenn es aus dem Bereich der realisierten Elemente herausgefallen ist.
  • ElementIndexChanged tritt für jedes realisierte Benutzeroberflächenelement (UIElement) auf, bei dem sich der Index des Elements, dem es entspricht, geändert hat. Wenn beispielsweise ein anderes Element in der Datenquelle hinzugefügt oder entfernt wird, empfängt der Index für Elemente, die in der Reihenfolge später kommen, dieses Ereignis.

In diesem Beispiel wird gezeigt, wie Sie diese Ereignisse dazu verwenden könnten, einen Auswahldienst anzufügen, um die Elementauswahl in einem benutzerdefinierten Steuerelement nachzuverfolgen, in dem „ItemsRepeater“ zum Anzeigen von Elementen verwendet wird.

<!-- xmlns:muxc="using:Microsoft.UI.Xaml.Controls" -->
<UserControl ...>
    ...
    <ScrollViewer>
        <muxc:ItemsRepeater ItemsSource="{x:Bind Items}"
                            ItemTemplate="{StaticResource MyTemplate}"
                            ElementPrepared="OnElementPrepared"
                            ElementIndexChanged="OnElementIndexChanged"
                            ElementClearing="OnElementClearing">
        </muxc:ItemsRepeater>
    </ScrollViewer>
    ...
</UserControl>
interface ISelectable
{
    int SelectionIndex { get; set; }
    void UnregisterSelectionModel(SelectionModel selectionModel);
    void RegisterSelectionModel(SelectionModel selectionModel);
}

private void OnElementPrepared(ItemsRepeater sender, ElementPreparedEventArgs args)
{
    var selectable = args.Element as ISelectable;
    if (selectable != null)
    {
        // Wire up this item to recognize a 'select' and listen for programmatic
        // changes to the selection model to know when to update its visual state.
        selectable.SelectionIndex = args.Index;
        selectable.RegisterSelectionModel(this.SelectionModel);
    }
}

private void OnElementIndexChanged(ItemsRepeater sender, ElementIndexChangedEventArgs args)
{
    var selectable = args.Element as ISelectable;
    if (selectable != null)
    {
        // Sync the ID we use to notify the selection model when the item
        // we represent has changed location in the data source.
        selectable.SelectionIndex = args.NewIndex;
    }
}

private void OnElementClearing(ItemsRepeater sender, ElementClearingEventArgs args)
{
    var selectable = args.Element as ISelectable;
    if (selectable != null)
    {
        // Disconnect handlers to recognize a 'select' and stop
        // listening for programmatic changes to the selection model.
        selectable.UnregisterSelectionModel(this.SelectionModel);
        selectable.SelectionIndex = -1;
    }
}

Sortieren, Filtern und Zurücksetzen der Daten

Wenn Sie eine Aktion wie Filtern oder Sortieren eines Datasets ausführen, besteht Ihre herkömmliche Vorgehensweise möglicherweise darin, den früheren Satz von Daten mit den neuen Daten zu vergleichen und dann granulare Änderungsbenachrichtigungen über INotifyCollectionChanged auszugeben. Häufig ist es jedoch einfacher, die alten Daten vollständig durch die neuen Daten zu ersetzen und mit der Reset-Aktion eine Änderungsbenachrichtigung für die Sammlung auszulösen.

In der Regel veranlasst ein Zurücksetzen ein Steuerelement dazu, vorhandene untergeordnete Elemente freizugeben und neu zu beginnen, wobei die Benutzeroberfläche ab dem Anfang an Scrollposition 0 erstellt wird, weil das Steuerelement nicht genau weiß, wie sich die Daten während des Zurücksetzens geändert haben.

Unterstützt die als Elementequelle (ItemsSource) zugewiesene Sammlung jedoch eindeutige Bezeichner, indem die IKeyIndexMapping-Schnittstelle implementiert ist, kann „ItemsRepeater“ schnell Folgendes ermitteln:

  • Wiederverwendbare „UIElement“-Objekte für Daten, die vor und nach dem Zurücksetzen vorhanden waren
  • Zuvor sichtbare Elemente, die entfernt wurden
  • Hinzugefügte neue Elemente, die sichtbar sind

Dadurch wird verhindert, dass „ItemsRepeater“ erneut bei der Scrollposition 0 beginnt. Außerdem wird „ItemsRepeater“ hiermit in die Lage versetzt, die „UIElement“-Objekte für Daten schnell wiederherzustellen, die beim Zurücksetzen nicht geändert wurden, wodurch eine bessere Leistung erzielt wird.

In diesem Beispiel wird gezeigt, wie eine Liste von Elementen in einem vertikalen Stapel angezeigt wird, wobei MyItemsSource eine benutzerdefinierte Datenquelle ist, die eine zugrunde liegende Liste von Elementen umschließt. Sie macht eine Data-Eigenschaft verfügbar, die dazu verwendet werden kann, eine neue Quelle zuzuweisen, die als Elementequelle zu verwenden ist, wodurch dann ein Zurücksetzen ausgelöst wird.

<ScrollViewer x:Name="sv">
    <ItemsRepeater x:Name="repeater"
                ItemsSource="{x:Bind MyItemsSource}"
                ItemTemplate="{StaticResource MyTemplate}">
       <ItemsRepeater.Layout>
           <StackLayout ItemSpacing="8"/>
       </ItemsRepeater.Layout>
   </ItemsRepeater>
</ScrollViewer>
public MainPage()
{
    this.InitializeComponent();

    // Similar to an ItemsControl, a developer sets the ItemsRepeater's ItemsSource.
    // Here we provide our custom source that supports unique IDs which enables
    // ItemsRepeater to be smart about handling resets from the data.
    // Unique IDs also make it easy to do things apply sorting/filtering
    // without impacting any state (i.e. selection).
    MyItemsSource myItemsSource = new MyItemsSource(data);

    repeater.ItemsSource = myItemsSource;

    // ...

    // We can sort/filter the data using whatever mechanism makes the
    // most sense (LINQ, database query, etc.) and then reassign
    // it, which in our implementation triggers a reset.
    myItemsSource.Data = someNewData;
}

// ...


public class MyItemsSource : IReadOnlyList<ItemBase>, IKeyIndexMapping, INotifyCollectionChanged
{
    private IList<ItemBase> _data;

    public MyItemsSource(IEnumerable<ItemBase> data)
    {
        if (data == null) throw new ArgumentNullException();

        this._data = data.ToList();
    }

    public IList<ItemBase> Data
    {
        get { return _data; }
        set
        {
            _data = value;

            // Instead of tossing out existing elements and re-creating them,
            // ItemsRepeater will reuse the existing elements and match them up
            // with the data again.
            this.CollectionChanged?.Invoke(
                this,
                new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
    }

    #region IReadOnlyList<T>

    public ItemBase this[int index] => this.Data != null
        ? this.Data[index]
        : throw new IndexOutOfRangeException();

    public int Count => this.Data != null ? this.Data.Count : 0;
    public IEnumerator<ItemBase> GetEnumerator() => this.Data.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();

    #endregion

    #region INotifyCollectionChanged

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    #endregion

    #region IKeyIndexMapping

    private int lastRequestedIndex = IndexNotFound;
    private const int IndexNotFound = -1;

    // When UniqueIDs are supported, the ItemsRepeater caches the unique ID for each item
    // with the matching UIElement that represents the item.  When a reset occurs the
    // ItemsRepeater pairs up the already generated UIElements with items in the data
    // source.
    // ItemsRepeater uses IndexForUniqueId after a reset to probe the data and identify
    // the new index of an item to use as the anchor.  If that item no
    // longer exists in the data source it may try using another cached unique ID until
    // either a match is found or it determines that all the previously visible items
    // no longer exist.
    public int IndexForUniqueId(string uniqueId)
    {
        // We'll try to increase our odds of finding a match sooner by starting from the
        // position that we know was last requested and search forward.
        var start = lastRequestedIndex;
        for (int i = start; i < this.Count; i++)
        {
            if (this[i].PrimaryKey.Equals(uniqueId))
                return i;
        }

        // Then try searching backward.
        start = Math.Min(this.Count - 1, lastRequestedIndex);
        for (int i = start; i >= 0; i--)
        {
            if (this[i].PrimaryKey.Equals(uniqueId))
                return i;
        }

        return IndexNotFound;
    }

    public string UniqueIdForIndex(int index)
    {
        var key = this[index].PrimaryKey;
        lastRequestedIndex = index;
        return key;
    }

    #endregion
}

Erstellen eines benutzerdefinierten Sammlungssteuerelements

Sie können ItemsRepeater verwenden, um ein benutzerdefiniertes Sammlungssteuerelement vollständig mit seinem eigenen Steuerungstyp zu erstellen, um jedes Element darzustellen.

Hinweis

Dies ist vergleichbar mit dem Verwenden von ItemsControl, aber statt von ItemsControl abzuleiten und eine ItemsPresenter-Instanz in die Steuerelementvorlage zu setzen, nehmen Sie das Ableiten von Control vor, und fügen Sie ein ItemsRepeater-Steuerelement in die Steuerelementvorlage ein. Das benutzerdefinierte Sammlungssteuerelement „hat ein“ ItemsRepeater-Steuerelement im Vergleich zu „ist ein“ ItemsControl-Steuerelement. Dies impliziert, Sie müssen auch explizit auswählen, welche Eigenschaften verfügbar zu machen sind, anstatt festzulegen, welche geerbten Eigenschaften nicht unterstützt werden sollen.

In diesem Beispiel wird gezeigt, wie ein ItemsRepeater-Steuerelement in der Vorlage eines benutzerdefinierten Steuerelements namens MediaCollectionView angeordnet wird und wie dessen Eigenschaften verfügbar gemacht werden.

<!-- xmlns:muxc="using:Microsoft.UI.Xaml.Controls" -->
<Style TargetType="local:MediaCollectionView">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MediaCollectionView">
                <Border
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}">
                    <ScrollViewer x:Name="ScrollViewer">
                        <muxc:ItemsRepeater x:Name="ItemsRepeater"
                                            ItemsSource="{TemplateBinding ItemsSource}"
                                            ItemTemplate="{TemplateBinding ItemTemplate}"
                                            Layout="{TemplateBinding Layout}"
                                            TabFocusNavigation="{TemplateBinding TabFocusNavigation}"/>
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
public sealed class MediaCollectionView : Control
{
    public object ItemsSource
    {
        get { return (object)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ItemsSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(MediaCollectionView), new PropertyMetadata(0));

    public DataTemplate ItemTemplate
    {
        get { return (DataTemplate)GetValue(ItemTemplateProperty); }
        set { SetValue(ItemTemplateProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ItemTemplate.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ItemTemplateProperty =
        DependencyProperty.Register(nameof(ItemTemplate), typeof(DataTemplate), typeof(MediaCollectionView), new PropertyMetadata(0));

    public Layout Layout
    {
        get { return (Layout)GetValue(LayoutProperty); }
        set { SetValue(LayoutProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Layout.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty LayoutProperty =
        DependencyProperty.Register(nameof(Layout), typeof(Layout), typeof(MediaCollectionView), new PropertyMetadata(0));

    public MediaCollectionView()
    {
        this.DefaultStyleKey = typeof(MediaCollectionView);
    }
}

Anzeigen von gruppierten Elementen

Sie können ein ItemsRepeater-Steuerelement in der ItemTemplate-Eigenschaft eines anderen ItemsRepeater-Steuerelements schachteln, um geschachtelte Virtualisierungslayouts zu erstellen. Das Framework nutzt Ressourcen effizient, indem es unnötige Verwendung (Realisierung) von Elementen minimiert, die nicht sichtbar sind oder sich in der Nähe des aktuellen Viewports befinden.

In diesem Beispiel wird veranschaulicht, wie Sie eine Liste von gruppierten Elementen in einem vertikalen Stapel anzeigen können. Das äußere „ItemsRepeater“-Steuerelement generiert jede Gruppe. In der Vorlage für jede Gruppe generiert ein anderes „ItemsRepeater“-Steuerelement die Elemente .

<!-- xmlns:muxc="using:Microsoft.UI.Xaml.Controls" -->

<Page.Resources>
    <muxc:StackLayout x:Key="MyGroupLayout"/>
    <muxc:StackLayout x:Key="MyItemLayout" Orientation="Horizontal"/>
</Page.Resources>

<ScrollViewer>
  <muxc:ItemsRepeater ItemsSource="{x:Bind AppNotifications}"
                      Layout="{StaticResource MyGroupLayout}">
    <muxc:ItemsRepeater.ItemTemplate>
      <DataTemplate x:DataType="ExampleApp:AppNotifications">
        <!-- Group -->
        <StackPanel>
          <!-- Header -->
          <TextBlock Text="{x:Bind AppTitle}"/>
          <!-- Items -->
          <muxc:ItemsRepeater ItemsSource="{x:Bind Notifications}"
                              Layout="{StaticResource MyItemLayout}"
                              ItemTemplate="{StaticResource MyTemplate}"/>
          <!-- Footer -->
          <Button Content="{x:Bind FooterText}"/>
        </StackPanel>
      </DataTemplate>
    </muxc:ItemsRepeater.ItemTemplate>
  </muxc:ItemsRepeater>
</ScrollViewer>

Die folgende Abbildung zeigt das grundlegende Layout, das auf Grundlage des obigen Beispiels erstellt wurde.

Geschachteltes Layouts mit „ItemsRepeater“-Steuerelement

Das nächste Beispiel zeigt ein Layout für eine App, in der es verschiedene Kategorien gibt, die mit der Benutzereinstellung geändert werden können und als horizontal scrollende Listen angezeigt werden. Das Layout dieses Beispiels wird auch in der obigen Abbildung dargestellt.

<!-- xmlns:muxc="using:Microsoft.UI.Xaml.Controls" -->
<!-- Include the <muxc:ItemsRepeaterScrollHost> if targeting Windows 10 versions earlier than 1809. -->
<ScrollViewer>
  <muxc:ItemsRepeater ItemsSource="{x:Bind Categories}"
                      Background="LightGreen">
    <muxc:ItemsRepeater.ItemTemplate>
      <DataTemplate x:DataType="local:Category">
        <StackPanel Margin="12,0">
          <TextBlock Text="{x:Bind Name}" Style="{ThemeResource TitleTextBlockStyle}"/>
          <!-- Include the <muxc:ItemsRepeaterScrollHost> if targeting Windows 10 versions earlier than 1809. -->
          <ScrollViewer HorizontalScrollMode="Enabled"
                                          VerticalScrollMode="Disabled"
                                          HorizontalScrollBarVisibility="Auto" >
            <muxc:ItemsRepeater ItemsSource="{x:Bind Items}"
                                Background="Orange">
              <muxc:ItemsRepeater.ItemTemplate>
                <DataTemplate x:DataType="local:CategoryItem">
                  <Grid Margin="10"
                        Height="60" Width="120"
                        Background="LightBlue">
                    <TextBlock Text="{x:Bind Name}"
                               Style="{StaticResource SubtitleTextBlockStyle}"
                               Margin="4"/>
                  </Grid>
                </DataTemplate>
              </muxc:ItemsRepeater.ItemTemplate>
              <muxc:ItemsRepeater.Layout>
                <muxc:StackLayout Orientation="Horizontal"/>
              </muxc:ItemsRepeater.Layout>
            </muxc:ItemsRepeater>
          </ScrollViewer>
        </StackPanel>
      </DataTemplate>
    </muxc:ItemsRepeater.ItemTemplate>
  </muxc:ItemsRepeater>
</ScrollViewer>

Bringen eines Elements in die Ansicht

Das XAML-Framework verwaltet bereits das Bringen eines Frameworkelements (FrameworkElement) in die Ansicht, wenn es entweder den 1) Tastaturfokus erhält oder den 2) Sprachausgabefokus erhält. Es kann weitere Fälle geben, in denen Sie ein Element explizit in die Ansicht bringen müssen. So beispielsweise als Antwort auf eine Benutzeraktion oder zum Wiederherstellen des Zustands der Benutzeroberfläche nach einer Seitennavigation.

Für ein Bringen eines virtualisierten Elements in die Ansicht sind folgende Schritt erforderlich:

  1. Realisieren eines „UIElement“-Objekts für ein Element
  2. Ausführen des Layouts, um sicherzustellen, dass das Element eine gültige Position hat
  3. Initiieren einer Anforderung, um das realisierte Element in die Anzeige zu bringen

Im folgenden Beispiel werden diese Schritte als Bestandteil der Wiederherstellung der Scrollposition eines Elements in einer flachen vertikalen Liste nach einer Seitennavigation veranschaulicht. Bei hierarchischen Daten mit geschachtelten „ItemsRepeater“-Steuerelementen ist die Vorgehensweise im Wesentlichen identisch, muss aber auf jeder Ebene der Hierarchie ausgeführt werden.

<ScrollViewer x:Name="scrollviewer">
  <ItemsRepeater x:Name="repeater" .../>
</ScrollViewer>
public class MyPage : Page
{
    // ...

     protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        // retrieve saved offset + index(es) of the tracked element and then bring it into view.
        // ... 
        
        var element = repeater.GetOrCreateElement(index);

        // ensure the item is given a valid position
        element.UpdateLayout();

        element.StartBringIntoView(new BringIntoViewOptions()
        {
            VerticalOffset = relativeVerticalOffset
        });
    }

    protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
    {
        base.OnNavigatingFrom(e);

        // retrieve and save the relative offset and index(es) of the scrollviewer's current anchor element ...
        var anchor = this.scrollviewer.CurrentAnchor;
        var index = this.repeater.GetElementIndex(anchor);
        var anchorBounds = anchor.TransformToVisual(this.scrollviewer).TransformBounds(new Rect(0, 0, anchor.ActualSize.X, anchor.ActualSize.Y));
        relativeVerticalOffset = this.scrollviewer.VerticalOffset - anchorBounds.Top;
    }
}

Aktivieren von Barrierefreiheit

ItemsRepeater stellt keine Standardbenutzeroberfläche für Barrierefreiheit bereit. Die Dokumentation zu Benutzerfreundlichkeit in Windows-Apps bietet eine Fülle von Informationen dazu, wie Sie sicherstellen können, dass Ihre App eine inklusive Benutzeroberfläche bereitstellt. Wenn Sie die „ItemsRepeater“-Klasse verwenden, um ein benutzerdefiniertes Steuerelement zu erstellen, sollten Sie die Dokumentation zu Benutzerdefinierte Automatisierungspeers lesen.

Tastaturunterstützung

Die Mindesttastaturunterstützung für Fokusbewegung, die „ItemsRepeater“ bietet, basiert auf der zu XAML gehörenden direktionalen 2D-Navigation für die Tastatur.

Richtungsnavigation (direktionale Navigation)

Der XYFocusKeyboardNavigation-Modus von „ItemsRepeater“ ist standardmäßig aktiviert (Enabled). Je nach gewünschter Oberfläche bietet es sich an, Unterstützung für allgemeine Tastaturinteraktionen, etwa „Pos1“ (Home), „Ende“ (End), „Bild auf“ (PageUp) und „Bild ab“ (PageDown), hinzuzufügen.

„ItemsRepeater“ stellt nicht automatisch sicher, dass die Standardaktivierreihenfolge für die enthaltenen Elemente (ob virtualisiert oder nicht) mit der Reihenfolge identisch ist, in der die Elemente in den Daten vorliegen. Standardmäßig ist die TabFocusNavigation-Eigenschaft von „ItemsRepeater“ auf Once anstelle der üblichen Standardeinstellung von Local festgelegt.

Hinweis

„ItemsRepeater“ merkt sich nicht automatisch das letzte fokussierte Element. Dies bedeutet, dass ein Benutzer, wenn er UMSCHALT+TAB verwendet, möglicherweise zum letzten realisierten Element gelangt.

Ankündigen von „Element X von Y“ in Sprachausgaben

Sie müssen das Festlegen der entsprechenden Automatisierungseigenschaften verwalten, z. B. die Werte für PositionInSet und SizeOfSet, und sicherstellen, dass sie auf dem neuesten Stand bleiben, wenn Elemente hinzugefügt, verschoben, entfernt usw. werden.

In einigen benutzerdefinierten Layouts gibt es möglicherweise keine offensichtliche Abfolge für die visuelle Reihenfolge. Benutzer erwarten zumindest, dass die Werte für die Eigenschaften „PositionInSet“ und „SizeOfSet“, die von Sprachausgaben verwendet werden, der Reihenfolge entsprechen, in der die Elemente in den Daten stehen (versetzt um 1, um der natürlichen Zählweise gegenüber 0-Basierung zu entsprechen).

Dies lässt sich am besten erreichen, indem im Automatisierungspeer für das Elementsteuerelement die Methoden GetPositionInSetCore und GetSizeOfSetCore implementiert werden und die Position des Elements im Dataset, das durch das Steuerelement dargestellt wird, mitgeteilt wird. Der Wert wird nur zur Laufzeit berechnet, wenn über eine Hilfstechnologie auf ihn zugegriffen wird. Somit ist es kein Problem, ihn auf dem neuesten Stand zu halten. Der Wert entspricht der Datenreihenfolge.

In diesem Beispiel wird gezeigt, wie Sie dies umsetzen können, wenn Sie ein benutzerdefiniertes Steuerelement namens CardControl präsentieren.

<ScrollViewer >
    <ItemsRepeater x:Name="repeater" ItemsSource="{x:Bind MyItemsSource}">
       <ItemsRepeater.ItemTemplate>
           <DataTemplate x:DataType="local:CardViewModel">
               <local:CardControl Item="{x:Bind}"/>
           </DataTemplate>
       </ItemsRepeater.ItemTemplate>
   </ItemsRepeater>
</ScrollViewer>
internal sealed class CardControl : CardControlBase
{
    protected override AutomationPeer OnCreateAutomationPeer() => new CardControlAutomationPeer(this);

    private sealed class CardControlAutomationPeer : FrameworkElementAutomationPeer
    {
        private readonly CardControl owner;

        public CardControlAutomationPeer(CardControl owner) : base(owner) => this.owner = owner;

        protected override int GetPositionInSetCore()
          => ((ItemsRepeater)owner.Parent)?.GetElementIndex(this.owner) + 1 ?? base.GetPositionInSetCore();

        protected override int GetSizeOfSetCore()
          => ((ItemsRepeater)owner.Parent)?.ItemsSourceView?.Count ?? base.GetSizeOfSetCore();
    }
}