I have an ItemsRepeater. I know I can get all of the elements with ItemsRepeater.ItemsSourceView
, but how can I figure out which ones are realized (and not virtualized) (e.g., for focusing the right-most realized item)?
Is the only way to iterate through the list with ItemsRepeater.TryGetElement
and see what returns non-null?
You can't do this statically (i.e. ask "at the given moment, which elements are realized?") beyond the TryGetElement
approach mentioned in the question.
Have you tried the ItemsRepeater's Lifecycle Events?
ElementPrepared occurs each time an element is made ready for use. This occurs for both a newly created element as well as an element that already exists and is being re-used from the recycle queue.
ElementClearing occurs immediately each time an element has been sent to the recycle queue, such as when it falls outside the range of realized items.
Check this sample code:
public class Person
{
public string Id { get; set; }
}
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
for (int i = 0; i < 10_000; i++)
{
People.Add(new Person { Id = $"{i + 1}" });
}
}
public ObservableCollection<Person> People { get; } = new();
public ObservableCollection<Person> LoadedItems { get; } = new();
private void ItemsRepeaterControl_ElementPrepared(ItemsRepeater sender, ItemsRepeaterElementPreparedEventArgs args)
{
if (sender.ItemsSourceView.GetAt(args.Index) is not Person item ||
args.Element is not FrameworkElement frameworkElement)
{
return;
}
frameworkElement.DataContext = item;
LoadedItems.Add(item);
}
private void ItemsRepeaterControl_ElementClearing(ItemsRepeater sender, ItemsRepeaterElementClearingEventArgs args)
{
if (args.Element is not FrameworkElement frameworkElement ||
frameworkElement.DataContext is not Person item)
{
return;
}
LoadedItems.Remove(item);
}
}
<Grid ColumnDefinitions="*,*">
<Grid.Resources>
<DataTemplate
x:Key="PersonItemTemplate"
x:DataType="local:Person">
<Grid>
<TextBlock Text="{x:Bind Id, Mode=OneWay}" />
</Grid>
</DataTemplate>
</Grid.Resources>
<Grid
Grid.Column="0"
RowDefinitions="Auto,*">
<TextBlock Grid.Row="0">
<Run Text="Items Count: " />
<Run Text="{x:Bind People.Count, Mode=OneWay}" />
</TextBlock>
<ScrollView Grid.Row="1">
<ItemsRepeater
ElementClearing="ItemsRepeaterControl_ElementClearing"
ElementPrepared="ItemsRepeaterControl_ElementPrepared"
ItemsSource="{x:Bind People, Mode=OneWay}">
<ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="local:Person">
<Grid>
<TextBlock Text="{x:Bind Id, Mode=OneWay}" />
</Grid>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ScrollView>
</Grid>
<Grid
Grid.Column="1"
RowDefinitions="Auto,*">
<TextBlock Grid.Row="0">
<Run Text="Loaded Count: " />
<Run Text="{x:Bind LoadedItems.Count, Mode=OneWay}" />
</TextBlock>
<ScrollView Grid.Row="1">
<ListView ItemsSource="{x:Bind LoadedItems, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Person">
<Grid>
<TextBlock Text="{x:Bind Id, Mode=OneWay}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollView>
</Grid>
</Grid>