Primary APIs:
ItemsControlItemsPresenterItemContainerGeneratorVirtualizingPanelVirtualizingStackPanelIRecyclingDataTemplateFuncDataTemplateImportant members:
ItemsControl.ItemsSource, Items, ItemsViewItemsControl.ItemTemplate, ItemsPanel, ItemContainerThemeItemsControl.ItemContainerGeneratorItemsPresenter.Panel, ScrollIntoView(...), ContainerFromIndex(...)ItemContainerGenerator.NeedsContainer(...)ItemContainerGenerator.CreateContainer(...)ItemContainerGenerator.PrepareItemContainer(...)ItemContainerGenerator.ItemContainerPrepared(...)ItemContainerGenerator.ClearItemContainer(...)VirtualizingPanel.ScrollIntoView(...), ContainerFromIndex(...), GetRealizedContainers()VirtualizingStackPanel.CacheLength, FirstRealizedIndex, LastRealizedIndexIRecyclingDataTemplate.Build(data, existing)FuncDataTemplate(..., supportsRecycling: true)Reference source files:
src/Avalonia.Controls/ItemsControl.cssrc/Avalonia.Controls/Presenters/ItemsPresenter.cssrc/Avalonia.Controls/Generators/ItemContainerGenerator.cssrc/Avalonia.Controls/VirtualizingPanel.cssrc/Avalonia.Controls/VirtualizingStackPanel.cssrc/Avalonia.Controls/Templates/IRecyclingDataTemplate.cssrc/Avalonia.Controls/Templates/FuncDataTemplate.csDefault high-level pipeline:
ItemsControl owns item source and template.ItemsPresenter creates panel from ItemsPanel.VirtualizingPanel, it realizes only visible range.ItemContainerGenerator prepares/clears containers.<ListBox ItemsSource="{Binding Rows}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" CacheLength="1.0" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
using Avalonia.Controls;
using Avalonia.Controls.Templates;
itemsControl.ItemTemplate = new FuncDataTemplate(
match: item => item is RowViewModel,
build: (_, _) => new RowView(),
supportsRecycling: true);
itemsControl.Presenter?.ScrollIntoView(index);
When deriving VirtualizingPanel, use ItemContainerGenerator in this order:
NeedsContainer(...)CreateContainer(...) when neededPrepareItemContainer(...)AddInternalChild(...) or InsertInternalChild(...)ItemContainerPrepared(...)ClearItemContainer(...)VirtualizingStackPanel for large linear lists.CacheLength for your scroll profile.ItemsPanel.ContainerFromIndex returns null unexpectedly:
ScrollIntoView(...) first.CacheLength too small for workload, causing churn.Default mode:
XAML-first complete example:
<ListBox xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:MyApp.ViewModels"
x:DataType="vm:ListPageViewModel"
ItemsSource="{CompiledBinding Rows}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel CacheLength="1.0" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate x:DataType="vm:RowViewModel">
<TextBlock Text="{CompiledBinding Title}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code-only alternative (on request):
using Avalonia.Controls.Templates;
listBox.ItemsSource = viewModel.Rows;
listBox.ItemTemplate = new FuncDataTemplate<RowViewModel>((row, _) =>
new TextBlock { Text = row.Title },
supportsRecycling: true);
listBox.Presenter?.ScrollIntoView(0);