How do you know which items are realized (non-virtualized) in an ItemsRepeater?

37 Views Asked by At

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?

1

There are 1 best solutions below

3
Andrew KeepCoding On BEST ANSWER

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.

Alternative: book-keeping

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>