Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Pomocí itemsRepeater můžete vytvářet vlastní prostředí kolekcí pomocí flexibilního systému rozložení, vlastních zobrazení a virtualizace.
Na rozdíl od ListViewitemsRepeater neposkytuje komplexní prostředí pro koncové uživatele – nemá žádné výchozí uživatelské rozhraní a neposkytuje žádné zásady týkající se zaměření, výběru nebo interakce uživatele. Je to stavební blok, který můžete použít k vytvoření vlastních prostředí založených na kolekci a vlastních ovládacích prvků. I když nemá žádné předdefinované zásady, umožňuje připojit zásady k vytvoření požadovaného prostředí. Můžete například definovat rozložení, které se má použít, zásady klávesnice, zásady výběru atd.
ItemsRepeater si můžete představit jako panel řízený daty, nikoli jako úplný ovládací prvek, jako je ListView. Zadáte kolekci datových položek, která se má zobrazit, šablonu položky, která vygeneruje prvek uživatelského rozhraní pro každou položku dat, a rozložení určující velikost a umístění prvků. Pak ItemsRepeater vytvoří podřízené prvky ze zdroje dat a zobrazí je podle rozložení a šablony položky. Zobrazené položky nemusí být homogenní, protože ItemsRepeater může načíst obsah představující datové položky na základě kritérií zadaných v selektoru šablony dat.
Je to správná kontrola?
Pomocí itemsRepeater můžete vytvořit vlastní displeje pro kolekce dat. I když se dá použít k prezentaci základní sady položek, můžete ji často použít jako prvek zobrazení v šabloně vlastního ovládacího prvku.
Pokud potřebujete ovládací prvek před spuštěním k zobrazení dat v seznamu nebo mřížce s minimálním přizpůsobením, zvažte použití objektu ListView nebo GridView.
ItemsRepeater nemá integrovanou kolekci Items. Pokud potřebujete kolekci Položek poskytnout přímo, a ne vazbu na samostatný zdroj dat, pravděpodobně potřebujete prostředí s vyššími zásadami a měli byste použít ListView nebo GridView.
ItemsControl i ItemsRepeater umožňují přizpůsobitelné prostředí kolekce, ale ItemsRepeater podporuje virtualizaci rozložení uživatelského rozhraní, zatímco ItemsControl ne. Místo ItemsControl doporučujeme použít ItemsRepeater, ať už jen pro prezentaci několika položek z dat nebo sestavení vlastního ovládacího prvku kolekce.
Posouvání pomocí ItemsRepeater
ItemsRepeater není odvozen od ovládacího prvku, takže nemá šablonu ovládacího prvku. Proto neobsahuje žádné předdefinované posouvání, jako je ListView nebo jiné ovládací prvky kolekce.
Pokud používáte ItemsRepeater, měli byste poskytnout funkci posouvání tak, že ji zabalíte do ovládacího prvku ScrollViewer .
Vytvořit objekt ItemsRepeater
- Důležitá rozhraní API: ItemsRepeater – třída, ScrollViewer – třída
![]()
Aplikace Galerie WinUI 3 obsahuje interaktivní příklady ovládacích prvků a funkcí WinUI. Získejte aplikaci z Microsoft Store nebo vyhledejte zdrojový kód na GitHub.
Chcete-li použít ItemsRepeater, musíte mu dát data, která se mají zobrazit nastavením ItemsSource vlastnost. Potom dejte vědět, jak zobrazit položky nastavením ItemTemplate vlastnost.
Zdroj položek
Pokud chcete zobrazení naplnit, nastavte vlastnost ItemsSource na kolekci datových položek. Zde je ItemsSource nastaven v kódu přímo na instanci kolekce.
ObservableCollection<string> Items = new ObservableCollection<string>();
ItemsRepeater itemsRepeater1 = new ItemsRepeater();
itemsRepeater1.ItemsSource = Items;
Vlastnost ItemsSource můžete také svázat s kolekcí v jazyce XAML. Další informace o datové vazbě najdete v tématu Přehled datových vazeb.
<ItemsRepeater ItemsSource="{x:Bind Items}"/>
Šablona položky
Pokud chcete určit, jak se datová položka vizualizuje, nastavte vlastnost ItemTemplate na DataTemplate nebo DataTemplateSelector , který jste definovali. Šablona dat definuje, jak se data vizualizují. Ve výchozím nastavení je položka v zobrazení zobrazena pomocí TextBlock, který používá řetězcovou reprezentaci datového objektu.
Obvykle ale chcete zobrazit bohatší prezentaci dat pomocí šablony, která definuje rozložení a vzhled jednoho nebo více ovládacích prvků, které použijete k zobrazení jednotlivé položky. Ovládací prvky, které používáte v šabloně, mohou být svázány s vlastnostmi datového objektu nebo mají definovaný statický obsah.
datová šablona
V tomto příkladu je datový objekt jednoduchým řetězcem. DataTemplate obsahuje obrázek nalevo od textu a TextBlock je stylizován tak, aby zobrazoval řetězec v modrozelené barvě.
Poznámka:
Při použití rozšíření x:Bind markup v DataTemplate, musíte zadat DataType (x:DataType) v DataTemplate.
<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>
Tady je postup, jak by se položky zobrazovaly při zobrazení s tímto objektem DataTemplate.
Počet prvků použitých v objektu DataTemplate pro položku může mít významný vliv na výkon, pokud zobrazení zobrazuje velký počet položek. Další informace a příklady použití DataTemplates k definování vzhledu položek v seznamu najdete v tématu Kontejnery položek a šablony.
Návod
Pro vaše pohodlí, pokud chcete deklarovat šablonu přímo (inline) namísto jako statický prostředek, můžete specifikovat DataTemplate nebo DataTemplateSelector jako přímého potomka ItemsRepeater. Bude přiřazena jako hodnota ItemTemplate vlastnost. Toto je například platné:
<ItemsRepeater ItemsSource="{x:Bind Items}">
<DataTemplate>
<!-- ... -->
</DataTemplate>
</ItemsRepeater>
Návod
Na rozdíl od ListView a jiných ovládacích prvků kolekce objekt ItemsRepeater nezabalí prvky z objektu DataTemplate s dalším kontejnerem položek, který obsahuje výchozí zásady, jako jsou okraje, odsazení, vizuály výběru nebo ukazatel na stav vizuálu. Místo toho ItemsRepeater zobrazí pouze to, co je definováno v DataTemplate. Pokud chcete, aby položky měly stejný vzhled jako položka zobrazení seznamu, můžete do šablony dat explicitně zahrnout kontejner, například ListViewItem. ItemsRepeater zobrazí vizuály ListViewItem , ale automaticky nevyužívá jiné funkce, jako je výběr nebo zobrazení zaškrtávacího políčka s vícenásobným zaškrtnutím.
Podobně platí, že pokud je kolekce dat kolekcí skutečných ovládacích prvků, jako je Button (List<Button>), můžete ovládací prvek zobrazit tak, že do dataTemplate vložíte ContentPresenter.
Výběr šablony dat
Položky, které se zobrazují v zobrazení, nemusí být stejného typu. Vlastnosti ItemTemplate můžete poskytnout DataTemplateSelector pro výběr různých DataTemplate na základě vámi zadaných kritérií.
Tento příklad předpokládá, že byl definován DataTemplateSelector, který rozhoduje mezi dvěma různými DataTemplate k reprezentaci velkých a malých položek.
<ItemsRepeater ...>
<ItemsRepeater.ItemTemplate>
<local:VariableSizeTemplateSelector Large="{StaticResource LargeItemTemplate}"
Small="{StaticResource SmallItemTemplate}"/>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
Při definování DataTemplateSelector pro použití s ItemsRepeater je nutné přepsat metodu SelectTemplateCore(Object). Další informace a příklady najdete v tématu DataTemplateSelector.
Poznámka:
Alternativou k DataTemplates ke správě způsobu vytváření prvků v pokročilejších scénářích je implementovat vlastní IElementFactory , které se mají použít jako ItemTemplate. Po vyžádání bude zodpovědný za generování obsahu.
Konfigurace zdroje dat
Vlastnost ItemsSource slouží k určení kolekce, která se má použít ke generování obsahu položek. ItemsSource můžete nastavit na libovolný typ, který implementuje IEnumerable. Další rozhraní kolekcí implementovaná vaším zdrojem dat určují, jaké funkce jsou k dispozici pro ItemsRepeater pro interakci s vašimi daty.
Tento seznam zobrazuje dostupná rozhraní a kdy zvážit jejich použití.
IEnumerable(.NET) / IIterable
Lze použít pro malé statické datové sady.
Alespoň musí zdroj dat implementovat rozhraní IEnumerable / IIterable. Pokud je to vše, co je podporováno, ovládací prvek iteruje všechno jednou a vytvoří kopii, kterou může použít k přístupu k položkám pomocí hodnoty indexu.
IReadonlyList(.NET) / IVectorView
Lze použít pro statické datové sady jen pro čtení.
Umožňuje ovládacímu prvku přístup k položkám podle indexu a zabrání redundantnímu internímu kopírování.
-
Lze použít pro statické datové sady.
Umožňuje ovládacímu prvku přístup k položkám podle indexu a zabrání redundantnímu internímu kopírování.
Upozornění: Změny seznamu/vektoru bez implementace INotifyCollectionChanged se neprojeví v uživatelském rozhraní.
INotifyCollectionChanged(.NET)
Doporučujeme podporovat oznámení o změnách.
Umožňuje ovládacímu prvku sledovat změny ve zdroji dat a reagovat na ně a odrážet je v uživatelském rozhraní.
-
Podporuje oznámení o změnách.
Podobně jako INotifyCollectionChanged rozhraní umožňuje ovládací prvek sledovat a reagovat na změny ve zdroji dat.
Upozornění: Windows.Foundation.IObservableVector<T> nepodporuje akci 'Přesunout'. To může způsobit ztrátu vizuálního stavu položky v uživatelském rozhraní. Například položka, která je aktuálně vybraná a/nebo má fokus, kde je přesunutí dosaženo pomocí příkazu Odebrat následovaného příkazem Přidat, ztratí fokus a už nebude vybraná.
Platform.Collections.Vector<T> používá IObservableVector<T> a má stejné omezení. Pokud je vyžadována podpora akce Přesunout, použijte rozhraní INotifyCollectionChanged. Třída .NET ObservableCollection<T> používá třídu INotifyCollectionChanged.
-
Pokud lze ke každé položce přidružit jedinečný identifikátor. Doporučuje se použít "Obnovit" pro změnu kolekce.
Umožňuje ovládacímu prvku velmi efektivně obnovit stávající uživatelské rozhraní po přijetí pevné akce Resetovat jako součást události INotifyCollectionChanged nebo IObservableVector . Po přijetí resetování ovládací prvek použije zadané jedinečné ID pro přidružení aktuálních dat k prvkům, které už vytvořil. Bez klíče k mapování indexu by musel ovládací prvek předpokládat, že musí začít od začátku při vytváření uživatelského rozhraní pro data.
Rozhraní uvedená výše, kromě IKeyIndexMapping, poskytují stejné chování v ItemsRepeater jako v ListView a GridView.
Následující rozhraní na ItemsSource umožňují speciální funkce v ovládacích prvcích ListView a GridView, ale v současné době nemají žádný vliv na ItemsRepeater:
- ISupportIncrementalLoading
- IItemsRangeInfo
- Informace o výběru
Alternativním přístupem k přírůstkovému načítání dat, když se uživatel posune nahoru nebo dolů, je sledovat pozici oblasti zobrazení ScrollVieweru a načíst další data, jakmile se oblast zobrazení přiblíží k rozsahu.
<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;
}
}
}
Změna rozložení položek
Položky zobrazené objektem ItemsRepeater jsou uspořádány objektem rozložení , který spravuje změnu velikosti a umístění jeho podřízených prvků. Při použití s ItemsRepeater objekt Layout umožňuje virtualizaci uživatelského rozhraní. K dispozici jsou rozložení StackLayout a UniformGridLayout. Ve výchozím nastavení itemsRepeater používá StackLayout se svislou orientací.
StackLayout
StackLayout uspořádá prvky do jedné čáry, kterou můžete orientovat vodorovně nebo svisle.
Vlastnost Mezery můžete nastavit tak, aby se upravila velikost mezery mezi položkami. Mezery se použijí ve směru rozložení orientace .
Tento příklad ukazuje, jak nastavit vlastnost ItemsRepeater.Layout na StackLayout s vodorovnou orientací a mezerou 8 pixelů.
<!-- 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 umístí prvky postupně v rozložení obtékání. Položky jsou rozloženy v pořadí odleva doprava, pokud je orientacevodorovná, a rozložení shora dolů, když je orientace svislá. Každá položka má stejnou velikost.
Počet položek v každém řádku vodorovného rozložení je ovlivněn minimální šířkou položky. Počet položek v každém sloupci svislého rozložení je ovlivněn minimální výškou položky.
- Minimální velikost, kterou chcete použít, můžete explicitně zadat nastavením vlastností MinItemHeight a MinItemWidth .
- Pokud nezadáte minimální velikost, bude naměřená velikost první položky považována za minimální velikost pro každou položku.
Nastavením vlastností MinColumnSpacing a MinRowSpacing můžete také nastavit minimální mezery pro rozložení, které se mají zahrnout mezi řádky a sloupci.
Po určení počtu položek v řádku nebo sloupci na základě minimální velikosti a mezery položky může po poslední položce řádku nebo sloupce zůstat nepoužité místo (jak je znázorněno na předchozím obrázku). Můžete určit, jestli se bude ignorovat nějaké nadbytečné místo, které se použije ke zvětšení velikosti každé položky, nebo k vytvoření nadbytečného místa mezi položkami. Tato vlastnost je řízena vlastnostmi ItemsStretch a ItemsJustification .
Vlastnost ItemsStretch můžete nastavit tak, aby se určilo, jak je velikost položky zvýšena, aby se vyplnil nevyužitý prostor.
Tento seznam zobrazuje dostupné hodnoty. Definice předpokládají, že výchozí orientace je vodorovná.
- Žádné: Nadbytečné místo zůstane nevyužité na konci řádku. Toto je výchozí hodnota.
- Výplň: Položky mají dodatečnou šířku, aby se využil dostupný prostor (výška, pokud je prostor svislý).
- Jednotné: Položky mají zvětšenou šířku, aby využily dostupný prostor, a zvýšenou výšku, aby zachovaly poměr stran (výška a šířka se vymění, pokud je vertikální).
Tento obrázek ukazuje efekt hodnot ItemsStretch ve vodorovném rozložení.
Když ItemsStretch je None, můžete nastavit ItemsJustification vlastnost určit, jak se k zarovnání položek použije nadbytečné místo.
Tento seznam zobrazuje dostupné hodnoty. Definice předpokládají, že výchozí orientace je vodorovná.
- Začátek: Položky jsou zarovnané se začátkem řádku. Nadbytečné místo zůstane nevyužité na konci řádku. Toto je výchozí hodnota.
- Střed: Položky jsou zarovnané na střed řádku. Nadbytečné místo je rovnoměrně rozděleno na začátek a na konci řádku.
- Konec: Položky jsou zarovnané s koncem řádku. Na začátku řádku zůstane nevyužité nadbytečné místo.
- SpaceAround: Položky se distribuují rovnoměrně. Stejné množství místa se přidá před a za každou položku.
- SpaceBetween: Položky se rovnoměrně distribuují. Mezi každou položku se přidá stejné množství místa. Na začátku a konci řádku se nepřidá mezera.
- SpaceEvenly: Položky se rovnoměrně distribuují se stejným množstvím mezer mezi každou položkou i na začátku a na konci řádku.
Tento obrázek znázorňuje efekt hodnot ItemsStretch ve svislém rozložení (použitém u sloupců místo řádků).
Návod
Vlastnost ItemsStretch ovlivňuje měřicí fázi rozložení. Vlastnost ItemsJustification má vliv na předání rozložení uspořádání.
Tento příklad ukazuje, jak nastavit ItemsRepeater.Layout vlastnost UniformGridLayout.
<!-- 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>
Události životního cyklu
Když hostujete položky v itemsRepeater, může být nutné provést nějakou akci, když je položka zobrazena nebo přestane být zobrazena, například spustit asynchronní stahování některého obsahu, přidružit prvek k mechanismu ke sledování výběru nebo zastavit úlohu na pozadí.
V virtualizujícím ovládacím prvku nelze spoléhat na události načtení/odstranění, protože prvek nemusí být odebrán z živého vizuálního stromu, když je recyklován. Místo toho jsou k dispozici další události pro správu životního cyklu prvků. Tento diagram znázorňuje životní cyklus prvku v ItemsRepeater a při vyvolání souvisejících událostí.
- ElementPrepared nastane pokaždé, když je prvek připravený k použití. K tomu dochází u nově vytvořeného elementu i elementu, který již existuje a který se znovu používá z fronty k recyklaci.
- ElementClearing se provádí okamžitě pokaždé, když byl prvek odeslán do fronty pro recyklaci, například když spadá mimo rozsah realizovaných položek.
- ElementIndexChanged se vyskytuje pro každý realizované UIElement, kde index položky, kterou představuje, se změnil. Pokud je například ve zdroji dat přidána nebo odebrána jiná položka, index pro položky, které přicházejí po objednávce, obdrží tuto událost.
Tento příklad ukazuje, jak můžete pomocí těchto událostí připojit službu vlastního výběru ke sledování výběru položek ve vlastním ovládacím prvku, který k zobrazení položek používá ItemsRepeater.
<!-- 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;
}
}
Řazení, filtrování a resetování dat
Při provádění akcí, jako je filtrování nebo řazení datové sady, můžete tradičně porovnat předchozí sadu dat s novými daty a pak vydat podrobná oznámení o změnách prostřednictvím INotifyCollectionChanged. Často je ale jednodušší úplně nahradit stará data novými daty a místo toho aktivovat oznámení o změně kolekce pomocí akce Resetovat .
Resetování obvykle způsobí, že ovládací prvek uvolní existující podřízené prvky a začne vytvářet uživatelské rozhraní úplně od začátku od pozice posunu 0, protože nemá povědomí o tom, jak se data během resetování změnila.
Pokud však kolekce přiřazená jako ItemsSource podporuje jedinečné identifikátory implementací IKeyIndexMapping rozhraní, pak ItemsRepeater může rychle identifikovat:
- opakovaně použitelné prvky uživatelského rozhraní pro data, která existovala před i po resetování
- dříve viditelné položky, které byly odebrány
- nové přidané položky, které budou viditelné
To umožňuje, aby ItemsRepeater nezačal znovu od pozice posunu 0. Umožňuje také rychle obnovit UIElements pro data, která se nezměnila během resetu, což vede k lepšímu výkonu.
Tento příklad ukazuje, jak zobrazit seznam položek ve svislém zásobníku, kde MyItemsSource je vlastní zdroj dat, který zabalí podkladový seznam položek. Zveřejňuje vlastnost Data , která se dá použít k opětovnému přiřazení nového seznamu, který se použije jako zdroj položek, a pak aktivuje resetování.
<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
}
Vytvořte vlastní ovládací prvek kolekce
ItemsRepeater můžete použít k vytvoření vlastního ovládacího prvku kolekce, který má svůj vlastní typ ovládacího prvku pro prezentaci každé položky.
Poznámka:
To se podobá použití ItemsControl, ale místo odvození z ItemsControl a umístění ItemsPresenter do šablony ovládacího prvku, odvozujete z Control a vložíte ItemsRepeater do šablony ovládacího prvku. Ovládací prvek vlastní kolekce "má" ItemsRepeater versus "je" ItemsControl. To znamená, že musíte také explicitně zvolit, které vlastnosti chcete zpřístupnit, namísto rozhodování, které zděděné vlastnosti nebudete podporovat.
Tento příklad ukazuje, jak umístit ItemsRepeater do šablony vlastního ovládacího prvku s názvem MediaCollectionView a zveřejnit jeho vlastnosti.
<!-- 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);
}
}
Zobrazení seskupených položek
Můžete vnořit ItemsRepeater do ItemTemplate jiného ItemsRepeater a vytvořit tak vnořená virtualizační rozložení. Rámec bude efektivně využívat prostředky tím, že minimalizuje zbytečné vykreslování prvků, které nejsou viditelné ani blízko aktuálního zorného pole.
Tento příklad ukazuje, jak můžete zobrazit seznam seskupených položek ve svislém zásobníku. Vnější ItemsRepeater vygeneruje každou skupinu. V šabloně pro každou skupinu vygeneruje další ItemsRepeater položky.
<!-- 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>
Následující obrázek znázorňuje základní rozložení vytvořené pomocí výše uvedeného vzorku jako vodítka.
Tento další příklad ukazuje rozložení pro aplikaci, která má různé kategorie, které se dají změnit pomocí uživatelských předvoleb, a zobrazí se jako vodorovné posouvání seznamů. Rozložení tohoto příkladu je znázorněno také výše uvedeným obrázkem.
<!-- 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>
Přenesení elementu do zobrazení
Architektura XAML už zpracovává přenesení prvku FrameworkElement do zobrazení, když buď 1) přijme fokus klávesnice, nebo 2) obdrží fokus od Předčítání. Můžou se zde vyskytovat i jiné případy, kdy je nutné explicitně přenést prvek do zobrazení. Například v reakci na akci uživatele nebo obnovení stavu uživatelského rozhraní po navigaci na stránce.
Přenesení virtualizovaného prvku do zobrazení zahrnuje následující:
- Realizace prvku UIElement pro položku
- Spusťte rozložení, abyste zajistili, že má prvek platnou pozici.
- Zahájení požadavku na zobrazení realizovaného prvku
Následující příklad ukazuje tyto kroky jako součást obnovení pozice posouvání položky v plochém svislém seznamu po navigaci na stránce. V případě hierarchických dat pomocí vnořených ItemsRepeaters je přístup v podstatě stejný, ale musí být proveden na každé úrovni hierarchie.
<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;
}
}
Povolení přístupnosti
ItemsRepeater neposkytuje výchozí prostředí přístupnosti. Dokumentace k Usability pro Windows aplikace poskytuje řadu informací, které vám pomůžou zajistit, aby vaše aplikace poskytovala inkluzivní uživatelské prostředí. Pokud k vytvoření vlastního ovládacího prvku používáte ItemsRepeater, nezapomeňte si prohlédnout dokumentaci k partnerským uzlům vlastní automatizace.
Klávesnice
Minimální podpora pohybu fokusu, který poskytuje ItemsRepeater, je založená na 2D navigační navigaci XAML pro klávesnici.
Režim XYFocusKeyboardNavigation u ItemsRepeater je ve výchozím nastavení povolen. V závislosti na zamýšleném prostředí zvažte přidání podpory běžných interakcí s klávesnicí , jako je Domů, Konec, PageUp a PageDown.
ItemsRepeater automaticky zajistí, že výchozí pořadí ovládacích prvků pro své položky (ať už virtualizované nebo ne) odpovídá stejnému pořadí, v jakém jsou položky uvedeny v datech. Ve výchozím nastavení má ItemsRepeater vlastnost TabFocusNavigation nastavenu na Once namísto běžné výchozí hodnoty Local.
Poznámka:
ItemsRepeater si automaticky nepamatuje poslední prioritní položku. To znamená, že když uživatel používá Shift+Tab, může být přesměrován na poslední dosaženou položku.
Oznámení položky X z Y v čtečkách obrazovky
Musíte spravovat nastavení odpovídajících vlastností automatizace, jako jsou hodnoty PositionInSet a SizeOfSet, a zajistit, aby zůstaly up-to-date při přidání, přesunutí, odebrání atd.
V některých vlastních rozvrženích nemusí existovat zřejmá posloupnost vizuálního uspořádání. Uživatelé minimálně očekávají, že hodnoty vlastností PositionInSet a SizeOfSet používané čtečkami obrazovky budou odpovídat pořadí, v jakém se položky zobrazují v datech (posun o 1, aby odpovídaly přirozenému počtu oproti 0).
Nejlepším způsobem, jak toho dosáhnout, je mít automatizační peer pro ovládací prvek položky, aby implementoval metody GetPositionInSetCore a GetSizeOfSetCore a hlásil pozici položky v datové sadě reprezentované ovládacím prvkem. Hodnota se počítá pouze za běhu, když k ní přistupuje asistenční technologie, a up-to-date udržování se tím stává nepodstatným. Hodnota odpovídá pořadí dat.
Tento příklad ukazuje, jak to můžete udělat při prezentování vlastního ovládacího prvku s názvem CardControl.
<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();
}
}
Související články
Windows developer