Lord Grosse Jeanine
Lord Grosse Jeanine

Reputation: 1131

IncrementalLoadingCollection loading all items right away in ListView

I'm writing an UWP app in C#. I have a page with a ListView taking all space available.

The list of items is huge so I use IncrementalLoadingCollection to load items gradually in the ListView while user is scrolling.

The problem is when I start the app all items are loaded right away in the ListView. GetPagedItemsAsync is called over and over and the app crashes throwing Layout cycle detected.

The only way I get the scroll loading to work is by fixing the ListView or height to a certain value. With fixed height on the ListView GetPagedItemsAsync is only called once at initialization and the scroll loading works as expected.

The thing is I want the ListView to fill page content so I don't want to set height to a specific value.

Page content

<Grid 
    HorizontalAlignment="Stretch" 
    VerticalAlignment="Stretch">

    <ListView 
        x:Name="channelList" 
        ItemsSource="{x:Bind Channels}"
        DataFetchSize="100" 
        IncrementalLoadingTrigger="Edge" 
        IncrementalLoadingThreshold="5" 
        HorizontalAlignment="Stretch" 
        VerticalAlignment="Stretch">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

</Grid>

Page class

public sealed partial class ChannelsPage : Page
{
    private IncrementalLoadingCollection<ChannelSource, ChannelModel> Channels { get; set; }

    public ChannelsPage()
    {
        this.InitializeComponent();
        Channels = new IncrementalLoadingCollection<ChannelSource, ChannelModel>();
    }

    private class ChannelSource : IIncrementalSource<ChannelModel>
    {
        private int Current { get; set; } = 0;
        private int Limit { get; set; } = 100;
        public async Task<IEnumerable<ChannelModel>> GetPagedItemsAsync(int pageIndex, int pageSize, CancellationToken cancellationToken = default(CancellationToken))
        {
            List<ChannelModel> channels = ChannelModel.List(false, Limit, Current);
            Current += Limit;
            return channels;
        }
    }
}

[Solved] The ListView was expanding out of bound due to a parent ScrollViewer in another file. Because of this continuous expansion out of its parent the items was loading non-stop.

Upvotes: 1

Views: 1189

Answers (1)

Martin Zikmund
Martin Zikmund

Reputation: 39082

The key to unlocking this mystery is the IncrementalLoadingThreshold. In simple terms it says the system how many "pages" of content to preload. In case you use 5, the system will make sure to have 5 times the height of the control ready to view. Try decreasing the value to 1 and you should see the method will be called once or twice. Even lower values like 0.1 are also possible.

Secondly, ensure you do not put the ListView into any layout control which allows it to expand beyond any bounds. For example, putting the list in a Grid.Row which has RowDefinition of Height="*" will make the list as long as it needs - which means it will keep loading items until there are no more available.

Finally, you need to make sure to indicate when you are out of items. This is easy if you return an empty IEnumerable from the method.

Upvotes: 3

Related Questions