Megosztás a következőn keresztül:


ItemsRepeater

Az ItemsRepeater használatával rugalmas elrendezési rendszer, egyéni nézetek és virtualizálás használatával hozhat létre egyéni gyűjteményszolgáltatásokat.

A ListView-tal ellentétben az ItemsRepeater nem nyújt átfogó végfelhasználói élményt – nincs alapértelmezett felhasználói felülete, és nem biztosít szabályzatot a fókusz, a kijelölés vagy a felhasználói interakció körében. Ehelyett ez egy építőelem, amellyel saját egyedi gyűjteményalapú felületeket és egyéni vezérlőket hozhat létre. Bár nem rendelkezik beépített szabályzattal, lehetővé teszi a szabályzat csatolását a szükséges felhasználói élmény kialakításához. Meghatározhatja például a használni kívánt elrendezést, a billentyűzethasználati szabályzatot, a kijelölési szabályzatot stb.

Az ItemsRepeater elméletileg adatvezérelt panelként is felfogható, nem pedig teljes vezérlőként, mint például a ListView. Megadhatja a megjelenítendő adatelemek gyűjteményét, egy olyan elemsablont, amely felhasználói felületi elemet hoz létre az egyes adatelemekhez, valamint egy elrendezést, amely meghatározza az elemek méretének és elhelyezésének módját. Ezután az ItemsRepeater gyermekelemeket hoz létre az adatforrás alapján, és az elemsablon és az elrendezés által meghatározott módon jeleníti meg őket. A megjelenített elemeknek nem kell homogénnek lenniük, mert az ItemsRepeater betölthet tartalmat, hogy az adatelemeket az adatsablon-választóban megadott feltételek alapján képviselje.

Ez a megfelelő vezérlő?

Az ItemsRepeater használatával egyéni kijelzőket hozhat létre adatgyűjteményekhez. Bár alapszintű elemek bemutatására is használható, gyakran használhatja megjelenítési elemként egy egyéni vezérlő sablonjában.

Ha egy lista vagy rács adatainak minimális testreszabással való megjelenítéséhez beépített vezérlőre van szüksége, fontolja meg a ListView vagy a GridView használatát.

Az ItemsRepeater nem rendelkezik beépített Elemek gyűjteménysel. Ha közvetlenül kell megadnia egy elemgyűjteményt, ahelyett, hogy külön adatforráshoz kötést hozna létre, akkor valószínűleg magasabb szintű funkcionalitásra van szüksége, és a ListView-t vagy a GridView-t kell használnia.

Az ItemsControl és az ItemsRepeater egyaránt lehetővé teszi a testre szabható gyűjteményszolgáltatásokat, de az ItemsRepeater támogatja a felhasználói felületi elrendezések virtualizálását, míg az ItemsControl nem. Az ItemsControl helyett az ItemsRepeater használatát javasoljuk, akár csak néhány adatelem bemutatásához, akár egyéni gyűjteményvezérlő létrehozásához.

Görgetés az ItemsRepeaterrel

Az ItemsRepeater nem a Vezérlőből származik, így nincs vezérlősablonja. Ezért nem tartalmaz olyan beépített görgetést, mint a ListView vagy más gyűjteményvezérlők.

Amikor ItemsRepeatert használ, a görgetési funkciót úgy biztosíthatja, hogy egy ScrollViewer vezérlőbe ágyazza be.

ItemsRepeater létrehozása

WinUI 3 Katalógus ikon A WinUI 3 Katalógus alkalmazás interaktív példákat tartalmaz a WinUI vezérlőire és funkcióira. Kérje le az alkalmazást a Microsoft Áruházból vagy keresse meg a forráskódot a GitHub webhelyen.

Az ItemsRepeater használatához meg kell adnia a megjelenítendő adatokat az ItemsSource tulajdonság beállításával. Ezután az ItemTemplate tulajdonság beállításával mondja el, hogyan jelenítheti meg az elemeket.

Elemforrás

A nézet feltöltéséhez állítsa az ItemsSource tulajdonságot adatelemek gyűjteményére. Itt az ItemsSource kódban közvetlenül egy gyűjteménypéldányra van beállítva.

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

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

Az ItemsSource tulajdonságot egy XAML-gyűjteményhez is kötheti. Az adatkötésről további információt az Adatkötés áttekintése című témakörben talál.

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

Tételsablon

Az adatelemek vizualizációjának megadásához állítsa az ItemTemplate tulajdonságot egy Ön által definiált DataTemplate vagy DataTemplateSelector értékre. Az adatsablon határozza meg az adatok vizualizációjának módját. Alapértelmezés szerint az elem egy TextBlock-tal jelenik meg a nézetben, amely az adatobjektum sztring-ábrázolását használja.

Általában azonban az adatok részletesebb bemutatását szeretné megjeleníteni egy sablon használatával, amely meghatározza egy vagy több vezérlő elrendezését és megjelenését, amelyet egy adott elem megjelenítéséhez fog használni. A sablonban használt vezérlők az adatobjektum tulajdonságaihoz köthetők, vagy statikus tartalomként közvetlenül meghatározhatók.

Adatsablon

Ebben a példában az adatobjektum egy egyszerű sztring. A DataTemplate tartalmaz egy képet a szöveg bal oldalán, és a TextBlock stílusával a szöveget tinószínben jeleníti meg.

Megjegyzés:

Ha a DataTemplate-ben használja az x:Bind jelölőbővítményt, meg kell adnia a DataTemplate DataType (x:DataType) attribútumát.

<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>

Az alábbi módon jelennek meg az elemek, amikor ezzel a DataTemplate-tal jelennek meg.

Adatsablonnal megjelenített elemek

Az elemek DataTemplate-jában használt elemek száma jelentős hatással lehet a teljesítményre, ha a nézet nagy számú elemet jelenít meg. További információ és példák a DataTemplates használatával a lista elemeinek megjelenésének meghatározásához: Elemtárolók és sablonok.

Jótanács

Ha a sablont nem statikus erőforrásként, hanem beágyazottként szeretné deklarálni, a DataTemplate vagy a DataTemplateSelectort az ItemsRepeater közvetlen gyermekeként adhatja meg. Ez lesz hozzárendelve az ItemTemplate tulajdonság értékeként. Ez például érvényes:

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

Jótanács

A ListView és más gyűjteményvezérlőktől eltérően az ItemsRepeater nem burkolja az elemeket egy DataTemplate-ból egy további elemtárolóval, amely alapértelmezett házirendet tartalmaz, például margókat, kitöltést, kijelölési vizualizációkat vagy mutatót a vizualizáció állapota felett. Ehelyett az ItemsRepeater csak a DataTemplate-ban definiált elemeket jeleníti meg. Ha azt szeretné, hogy az elemek ugyanúgy jelenjenek meg, mint egy listanézetelem, explicit módon belefoglalhat egy tárolót (például a ListViewItemet) az adatsablonba. Az ItemsRepeater megjeleníti a ListViewItem-vizualizációkat , de nem használja automatikusan más funkciókat, például a kijelölést vagy a többszörös kijelölési jelölőnégyzetet.

Hasonlóképpen, ha az adatgyűjtés tényleges vezérlők gyűjteménye, például Gomb (List<Button>), a DataTemplate-ban egy ContentPresentert is elhelyezhet a vezérlő megjelenítéséhez.

Adatsablonválasztó

A nézetben megjelenített elemeknek nem kell azonos típusúaknak lenniük. Az ItemTemplate tulajdonságot megadhatja egy DataTemplateSelectorrel , amellyel különböző DataTemplate-elemeketválaszthat ki a megadott feltételek alapján.

Ez a példa feltételezi, hogy egy DataTemplateSelector van meghatározva, amely két különböző DataTemplate-elemközött határoz meg egy nagy és egy kis elemet.

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

Az ItemsRepeaterrel használható DataTemplateSelector definiálásakor csak felülbírálást kell implementálnia a SelectTemplateCore(Object) metódushoz. További információkért és példákért lásd: DataTemplateSelector.

Megjegyzés:

A DataTemplates alternatívája az elemek speciálisabb forgatókönyvekben való létrehozásának kezelésére, ha saját IElementFactory-t implementál az ItemTemplate-ként való használatra. A tartalom kérése esetén az ő feladata lesz a tartalom generálása.

Az adatforrás konfigurálása

Az ItemsSource tulajdonság használatával adja meg az elemek tartalmának létrehozásához használni kívánt gyűjteményt. Az ItemsSource-t bármilyen olyan típusra beállíthatja, amely megvalósítja az IEnumerablet. Az adatforrás által implementált további gyűjtési felületek határozzák meg, hogy milyen funkciók érhetők el az ItemsRepeater számára az adatok kezeléséhez.

Ez a lista megjeleníti az elérhető felületeket, és hogy mikor érdemes megfontolni az egyes felületek használatát.

  • IEnumerable(.NET) / IIterable

    • Kis, statikus adatkészletekhez használható.

      Legalább az adatforrásnak implementálnia kell az IEnumerable/IIterable interfészt. Ha ez az összes, ami támogatott, akkor a vezérlő mindenen végigmegy egyszer, hogy létrehozhasson egy másolatot, amellyel indexértékkel elemekhez férhet hozzá.

  • IReadonlyList(.NET) / IVectorView

    • Használható statikus, csak olvasható adatkészletekhez.

      Lehetővé teszi, hogy a vezérlő index alapján érje el az elemeket, és elkerülje a redundáns belső másolást.

  • IList(.NET) / IVector

    • Statikus adatkészletekhez használható.

      Lehetővé teszi, hogy a vezérlő index alapján érje el az elemeket, és elkerülje a redundáns belső másolást.

      Figyelmeztetés: A lista/vektor INotifyCollectionChanged implementálása nélküli módosításai nem jelennek meg a felhasználói felületen.

  • INotifyCollectionChanged(.NET)

    • Javasolt a változásértesítés támogatása.

      Lehetővé teszi, hogy a vezérlő megfigyelje és reagáljon az adatforrás változásaira, és tükrözze a felhasználói felületen megjelenő változásokat.

  • IObservableVector

    • Támogatja a változásértesítést

      Az INotifyCollectionChanged interfészhez hasonlóan ez lehetővé teszi a vezérlő számára az adatforrás változásainak megfigyelését és reagálását.

      Warning: A Windows. A Foundation.IObservableVector<T> nem támogatja az áthelyezési műveletet. Ez azt okozhatja, hogy egy elem felhasználói felülete elveszíti a vizualizáció állapotát. Ha például egy elem éppen ki van jelölve, és/vagy fókuszban van, ahol az áthelyezést egy "Eltávolítás" és egy "Hozzáadás" követi, elveszíti a fókuszt, és többé nem lesz kijelölve.

      A Platform.Collections.Vector<T> az IObservableVector<T> használja, és ugyanezzel a korlátozásokkal rendelkezik. Ha "Áthelyezés" művelet támogatása szükséges, használja az INotifyCollectionChanged felületet. A .NET ObservableCollection<T> osztály az INotifyCollectionChanged-t használja.

  • IKeyIndexMapping

    • Ha minden elemhez egyedi azonosító társítható. Ajánlott az "Alaphelyzetbe állítás" használata esetén a gyűjteménymódosítási műveletként.

      Lehetővé teszi a vezérlő számára, hogy nagyon hatékonyan helyreállítsa a meglévő felhasználói felületet, miután egy INotifyCollectionChanged vagy IObservableVector esemény részeként kemény "Visszaállítás" műveletet kapott. Az alaphelyzetbe állítást követően a vezérlő a megadott egyedi azonosítóval társítja az aktuális adatokat a már létrehozott elemekhez. Az indexleképezés kulcsa nélkül a vezérlőnek feltételeznie kell, hogy az alapoktól kell kezdenie a felhasználói felület létrehozását az adatokhoz.

A fent felsorolt felületek, az IKeyIndexMapping kivételével, ugyanazt a viselkedést biztosítják az ItemsRepeaterben, mint a ListView-ban és a GridView-ban.

Az ItemsSource következő felületei speciális funkciókat tesznek lehetővé a ListView és a GridView vezérlőkben, de jelenleg nincs hatással az ItemsRepeaterre:

Az adatok növekményes betöltésének másik módszere, ha a felhasználó felfelé vagy lefelé görget, megfigyelheti a ScrollViewer nézetportjának pozícióját, és több adatot tölthet be, ahogy a nézetport megközelíti a mértéket.

<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;
        }
    }
}

Elemek elrendezésének módosítása

Az ItemsRepeater által megjelenített elemeket egy elrendezési objektum rendezi, amely kezeli a gyermekelemek méretezését és elhelyezését. Az ItemsRepeaterrel való használat esetén az Elrendezés objektum engedélyezi a felhasználói felület virtualizálását. A megadott elrendezések a StackLayout és a UniformGridLayout. Az ItemsRepeater alapértelmezés szerint függőleges tájolású StackLayoutot használ.

StackLayout

A StackLayout egyetlen sorba rendezi az elemeket, amelyeket vízszintesen vagy függőlegesen is eligazíthat.

A Térköz tulajdonság beállításával módosíthatja az elemek közötti térközt. A térközt az elrendezés tájolása irányába alkalmazza a rendszer.

Verem elrendezési távolság

Ez a példa bemutatja, hogyan állíthatja be az ItemsRepeater.Layout tulajdonságot stackLayout értékre vízszintes tájolással és 8 képpontos térközrel.

<!-- 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

A UniformGridLayout egymás után rendezi az elemeket egy körbefuttatási elrendezésben. Az elemek elrendezése balról jobbra, amikor az tájolásvízszintes, és felülről lefelé, amikor a tájolás függőleges. Minden elem egyenlő méretű.

Egységes rácselrendezés távolsága

A vízszintes elrendezés egyes soraiban lévő elemek számát a minimális elemszélesség befolyásolja. A függőleges elrendezés egyes oszlopaiban lévő elemek számát a minimális elemmagasság befolyásolja.

  • A MinItemHeight és a MinItemWidth tulajdonságok beállításával explicit módon megadhat egy minimális méretet.
  • Ha nem ad meg minimális méretet, az első elem mért mérete az elemenkénti minimális méretnek számít.

A MinColumnSpacing és a MinRowSpacing tulajdonságok beállításával beállíthatja az elrendezés minimális térközét is, hogy sorokat és oszlopokat tartalmazzon.

Egységes rácsméretezés és térköz

Ha egy sor vagy oszlop elemeinek számát az elem minimális mérete és térköze alapján határozták meg, előfordulhat, hogy a sor vagy oszlop utolsó eleme után (az előző képen látható módon) nem használt terület marad. Megadhatja, hogy a rendszer figyelmen kívül hagyja-e a felesleges szóközt, növelje-e az egyes elemek méretét, vagy használjon-e további szóközt az elemek között. Ezt az ItemsStretch és az ItemsJustification tulajdonságok vezérlik.

Az ItemsStretch tulajdonság beállításával megadhatja, hogy az elem mérete hogyan legyen növelve a fel nem használt terület kitöltéséhez.

Ez a lista az elérhető értékeket jeleníti meg. A definíciók az alapértelmezett vízszintestájolást feltételezik.

  • Nincs: A sor végén extra hely marad kihasználatlanul. Ez az alapértelmezett érték.
  • Kitöltés: Az elemek extra szélességet kapnak, hogy kihasználják a rendelkezésre álló teret (magasságot, ha függőleges az elrendezés).
  • Egységes: Az elemek extra szélességet kapnak a rendelkezésre álló terület használatához, és extra magasságot kapnak az oldalarány fenntartása érdekében (függőlegesen a magasság és a szélesség váltható).

Ez a kép az ItemsStretch értékek hatását jeleníti meg vízszintes elrendezésben.

Egységes rácselem nyúlik

Ha az ItemsStretchértéke Nincs, beállíthatja az ItemsJustification tulajdonságot, hogy meghatározza, hogyan használják fel a többletterületet az elemek igazításához.

Ez a lista az elérhető értékeket jeleníti meg. A definíciók az alapértelmezett vízszintestájolást feltételezik.

  • Kezdés: Az elemek a sor elejéhez vannak igazítva. A sor végén további hely marad használaton kívül. Ez az alapértelmezett érték.
  • Középre: Az elemek a sor közepén igazítódnak. A sor elején és végén egyenletesen oszlik el az extra térköz.
  • Vége: Az elemek a sor végére vannak igazítva. A sor elején további hely marad használaton kívül.
  • SpaceAround: Az elemek egyenletesen vannak elosztva. Minden elem előtt és után egyenlő mennyiségű hely adódik hozzá.
  • SpaceBetween: Az elemek egyenletesen vannak elosztva. Az egyes elemek között egyenlő mennyiségű térköz van hozzáadva. A sor elején és végén nincs hozzáadva szóköz.
  • SpaceEvenly: Az elemek egyenlően vannak elosztva, egyenlő mennyiségű szóközzel az egyes elemek között, valamint a sor elején és végén.

Ez a kép az ItemsStretch értékek hatását mutatja függőleges elrendezésben (sorok helyett oszlopokra alkalmazva).

Egységes rácselem igazítása

Jótanács

Az ItemsStretch tulajdonság befolyásolja az elrendezés mérési szakaszát. Az ItemsJustification tulajdonság hatással van az elrendezés elrendezési lépésére.

Ez a példa bemutatja, hogyan állíthatja be az ItemsRepeater.Layout tulajdonságotUniformGridLayout értékre.

<!-- 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>

Életciklus-események

Amikor elemeket üzemeltet egy ItemsRepeaterben, előfordulhat, hogy valamilyen műveletet kell végrehajtania, amikor egy elem megjelenik vagy leáll, például elindít egy tartalom aszinkron letöltését, társítja az elemet egy olyan mechanizmussal, amely nyomon követi a kijelölést, vagy leállítja a háttérfeladatot.

Virtualizálási vezérlőkben nem hagyatkozhat a Betöltés/Kiürítés eseményekre, mert előfordulhat, hogy az elemet nem távolítják el az élő vizuális fárol, amikor újrahasznosítják. Ehelyett más események is rendelkezésre állnak az elemek életciklusának kezeléséhez. Ez az ábra egy ItemsRepeater-elem életciklusát és a kapcsolódó események felmerülésének időpontját mutatja be.

Életciklus-eseménydiagram

  • Az ElementPrepared minden alkalommal megtörténik, amikor egy elem használatra készen áll. Ez mind az újonnan létrehozott, mind a már létező és a lomtári üzenetsorból újrahasznált elem esetében fordul elő.
  • Az ElementClearing azonnal megtörténik minden alkalommal, amikor egy elemet elküldenek az újrafelhasználási sorba, például amikor az a megvalósított elemek tartományán kívül esik.
  • Az ElementIndexChanged minden olyan realizált UIElement esetében történik, ahol az elem indexe megváltozott. Ha például egy másik elemet ad hozzá vagy távolít el az adatforrásban, a rendelésben szereplő elemek indexe megkapja ezt az eseményt.

Ez a példa bemutatja, hogyan használhatja ezeket az eseményeket egy egyéni kijelölési szolgáltatás csatolására egy elemkijelölés nyomon követésére egy egyéni vezérlőben, amely az Elemekrepeater használatával jeleníti meg az elemeket.

<!-- 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;
    }
}

Adatok rendezése, szűrése és alaphelyzetbe állítása

Amikor olyan műveleteket hajt végre, mint az adatkészlet szűrése vagy rendezése, előfordulhat, hogy az előző adatkészletet összehasonlította az új adatokkal, majd részletes változásértesítéseket adott ki az INotifyCollectionChanged használatával. Gyakran azonban egyszerűbb teljesen lecserélni a régi adatokat az új adatokra, és ehelyett a Visszaállítás művelettel aktiválni a gyűjteménymódosítási értesítést.

Az alaphelyzetbe állítás általában azt eredményezi, hogy egy vezérlő felszabadítja a meglévő gyermekelemeket, és újrakezdi a felhasználói felületet a 0. görgetési pozícióból kiindulva, mivel nem tudja pontosan, hogyan változtak az adatok az alaphelyzetbe állítás során.

Ha azonban az ItemsSource-ként hozzárendelt gyűjtemény az IKeyIndexMapping felület implementálásával támogatja az egyedi azonosítókat, az ItemsRepeater gyorsan azonosíthatja a következőket:

  • Újrahasználható UI-elemek létező adatokhoz, amelyek az alaphelyzetbe állítás előtt és után is fennállnak.
  • korábban látható, de eltávolított elemek
  • új elemek hozzáadva, amelyek láthatóak lesznek

Ez lehetővé teszi, hogy az ItemsRepeater ne kezdjen újra a 0 görgetési pozícióból. Lehetővé teszi továbbá, hogy gyorsan helyreállítsa azokat a felhasználói felületelemeket, amelyek olyan adatokhoz kapcsolódnak, amelyek nem változtak meg egy visszaállítás során, ami jobb teljesítményt eredményez.

Ez a példa bemutatja, hogyan jelenítheti meg a függőleges veremben lévő elemek listáját, ahol a MyItemsSource egy egyéni adatforrás, amely az elemek mögöttes listáját burkolja. Elérhetővé tesz egy Data tulajdonságot, amellyel újra hozzárendelhet egy új listát, amelyet az elemek forrásaként használ, majd alaphelyzetbe állítást indít el.

<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
}

Egyéni gyűjteményvezérlő létrehozása

Az ItemsRepeater használatával létrehozhat egy egyéni gyűjteményvezérlőt, amely saját típusú vezérlővel rendelkezik az egyes elemek megjelenítéséhez.

Megjegyzés:

Ez hasonló az ItemsControlhoz, de ahelyett, hogy ItemsControlból származtatna és egy ItemsPresentert helyezne a vezérlősablonba, a Controlból származtat és beszúr egy ItemsRepeatert a vezérlősablonba. Az egyéni gyűjtemény vezérlőelem egy ItemsRepeater-t tartalmaz, szemben azzal, hogy egy ItemsControl típusa. Ez azt jelenti, hogy explicit módon ki kell választania, hogy mely tulajdonságokat tegye közzé, ahelyett, hogy melyik örökölt tulajdonságokat ne támogassa.

Ez a példa bemutatja, hogyan helyezhet el egy ItemsRepeatert egy MediaCollectionView nevű egyéni vezérlő sablonjában, és hogyan teheti közzé a tulajdonságait.

<!-- 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);
    }
}

Csoportosított elemek megjelenítése

Egy ItemsRepeater egy másik ItemsRepeater ItemTemplate elemtáblájában ágyazható be beágyazott virtualizálási elrendezések létrehozásához. A keretrendszer hatékonyan fogja használni az erőforrásokat azáltal, hogy minimalizálja a nem látható vagy az aktuális nézetport közelében lévő elemek szükségtelen megvalósítását.

Ez a példa bemutatja, hogyan jelenítheti meg a csoportosított elemek listáját egy függőleges veremben. A külső ItemsRepeater minden csoportot létrehoz. Az egyes csoportok sablonjában egy másik ItemsRepeater hozza létre az elemeket.

<!-- 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>

Az alábbi képen az alapszintű elrendezés látható, amely a fenti minta alapján készült, útmutatóként.

Beágyazott elrendezés ismétlődő elemekkel

Ez a következő példa egy olyan alkalmazás elrendezését mutatja be, amely különböző kategóriákkal rendelkezik, amelyek felhasználói beállítások szerint változhatnak, és vízszintesen görgethető listákként jelennek meg. A példa elrendezését a fenti kép is ábrázolja.

<!-- 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>

Egy elem megjelenítése a nézetben

Az XAML-keretrendszer már kezeli egy elem megjelenítését, amikor az 1) billentyűzetfókuszt kap, vagy 2) Narrátor fókuszba kerül. Lehetnek más esetek is, amikor explicit módon meg kell jelenítenie egy elemet. Például egy felhasználói műveletre vagy a felhasználói felület állapotának visszaállítására válaszul egy lapnavigáció után.

A virtualizált elemek megtekintéséhez a következőkre van szükség:

  1. Elem felhasználói felületének megvalósítása
  2. Futtassa az elrendezést annak ellenőrzéséhez, hogy az elem rendelkezik-e érvényes pozícióval
  3. A megvalósult elem megtekintésére irányuló kérés kezdeményezése

Az alábbi példa ezeket a lépéseket mutatja be annak részeként, hogy egy elem görgetési pozícióját visszaállítja egy vízszintes, függőleges listában egy oldalnavigáció után. Beágyazott ItemsRepeaters használatával végzett hierarchikus adatok esetében a megközelítés lényegében ugyanaz, de a hierarchia minden szintjén el kell végezni.

<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;
    }
}

Akadálymentesség engedélyezése

Az ItemsRepeater nem biztosít alapértelmezett akadálymentességi élményt. A A Windows-alkalmazások használhatóságáról szóló dokumentáció számos információt tartalmaz, amelyek segítenek abban, hogy az alkalmazás befogadó felhasználói élményt nyújtson. Ha az ItemsRepeater használatával hoz létre egyéni vezérlőt, mindenképpen tekintse meg az egyéni automatizálási társokkal kapcsolatos dokumentációt.

Gépelés

Az ItemsRepeater által biztosított fókuszmozgatás minimális billentyűzetes támogatása az XAML 2D irányú billentyűzetes navigációján alapul.

Iránynavigáció

Az ItemsRepeater XYFocusKeyboardNavigation üzemmódja alapértelmezés szerint engedélyezve van. A kívánt felülettől függően érdemes lehet támogatást nyújtani a gyakori billentyűzet-interakciókhoz , például a Kezdőlaphoz, a Befejezéshez, a PageUphoz és a PageDownhoz.

Az ItemsRepeater automatikusan biztosítja, hogy az elemek alapértelmezett lapsorrendje (akár virtualizált, akár nem) ugyanazt a sorrendet követi, mint az adatokban. Alapértelmezés szerint az ItemsRepeater TabFocusNavigation tulajdonsága Egyszer értékre van állítva a helyiáltalános alapértelmezése helyett.

Megjegyzés:

Az ItemsRepeater nem emlékszik automatikusan az utolsó szűrt elemre. Ez azt jelenti, hogy amikor egy felhasználó a Shift+Tab billentyűkombinációt használja, előfordulhat, hogy az utolsó megvalósult elemhez kerül.

Az "Yelem X elemének" bejelentése a képernyőolvasókban

Kezelnie kell a megfelelő automatizálási tulajdonságokat, például a PositionInSet és a SizeOfSet értékeit, és gondoskodnia kell arról, hogy az elemek hozzáadása, áthelyezése, eltávolítása stb. up-todátumon maradjanak.

Egyes egyéni elrendezésekben előfordulhat, hogy a vizualizáció sorrendje nem egyértelmű. A felhasználók minimálisan elvárják, hogy a képernyőolvasók által használt PositionInSet és SizeOfSet tulajdonságok értékei kövessék az adatokban szereplő elemek sorrendjét (1-gyel eltolva annak érdekében, hogy a természetes számláláshoz igazodjon, szemben a 0-alapúval).

Ennek legjobb módja, ha az elemvezérlő automatizálási társával implementálja a GetPositionInSetCore és a GetSizeOfSetCore metódust , és jelentést ad az elem pozíciójáról a vezérlő által képviselt adatkészletben. Az érték csak futásidőben lesz kiszámítva, ha egy kisegítő technológia hozzáfér, és a dátum up-tomegtartása nem lesz probléma. Az érték megegyezik az adatsorrenddel.

Ez a példa bemutatja, hogyan teheti ezt meg egy CardControl nevű egyéni vezérlő bemutatásakor.

<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();
    }
}