2
votes

I have a listview in my UWP (Windows 10) application. Ideally it will load 100 items when application starts.

When list is scrolled to bottom i.e. to the last item in listview, API call will go & will load another 100 items & so on..

Here is my code :

<ListView x:Name="lstSuggestions" Height="200" Width="250" Foreground="#333eb4" HorizontalAlignment="Left" Margin="60,10" SelectionChanged="lstSuggestions_SelectionChanged"></ListView>

following call binds the listview (first 100 items on app start) :

public async void GetData(string Id, string limit)
    { 
        string mainUrlForSuggestions = ApiUrl +  "&id=" + d;
        string finalSelCharas = "";

        using (var httpClient = new HttpClient())
        {
            var dataUri = await httpClient.GetStringAsync(mainUrlForSuggestions);
            JsonObject jsonObject = JsonObject.Parse(dataUri.ToString());
            JsonArray jsonArray = jsonObject["payload"].GetArray();
            foreach (JsonValue groupValue in jsonArray)
            {
                JsonObject groupObject = groupValue.GetObject();
                lstSuggestionsAdd.Add(new SuggestedWords { Name = groupObject.GetNamedString("sug_name"), ID = groupObject.GetNamedString("id") });
            }
            lstSuggestions.ItemsSource = lstSuggestionsAdd;
        } 
    }

on app start limit is 100, once list reaches to an end, it must set limit to 200 or next 100 items and make an API call again.

I tried to achieve this with pointerEntered event. But, couldn't achieve the said functionality as it only matches the height assigned to listview with pointer height, so that wont work as scrollviewer height can vary. I even tried to get access to scrollviewer, but couldn't!

I have also referred following URL's : How do I allow a UWP ListView to scroll past the last item? && Detect when WPF listview scrollbar is at the bottom? && https://social.msdn.microsoft.com/Forums/windows/en-US/63b4b530-61d8-477f-af96-87e33260c919/uwa-how-to-detect-the-end-and-the-start-of-listview-and-load-more-data-items?forum=wpdevelop

But none of them actually worked in my case.

I tried to find an event to achieve this functionality, but didn't find any.

Can anyone give an idea about how to detect if listview scrolling reached to an end (last item in the listview)???

Note that i am working on windows 10 UWP application & not win 8

1
We are missing some info: 1) what does lstSuggestions_PointerEntered look like? 2) is it being called? (test it with a break point) 3) isn't there some on onitem_visible-like event?Stefan
@Stefan lstSuggestions_PointerEntered is called whenever the pointer is moved to listview area/section. It just captures whether the pointer is in listview UI areaace
I can't seem to see what your actual issue is. Are the items added to the listview? If so, can you scroll them into view?Stefan
@Stefan first 100 items are added into the list view & is able to scroll too. suppose now if user scrolled to last item the I want to load next 100 items into listview. I have mentioned the same thing in question tooace
My code will load the first 100 items in listview, once list is scrolled to last item/bottom it should load another 100 items. In this case it doesn't matter if i include lstSuggestions_PointerEntered or not. You can refer to this answer : [Detect when WPF listview scrollbar is at the bottom? ] (stackoverflow.com/a/37430977/8024811) however it doesn't helped in my caseace

1 Answers

4
votes

Ok, it's a bit different, It uses the ListView's incremental loading functionality to create a infinite scrolling list.

This means you won't have as much control of loading the data as you assumed in your question, but still I think it will suit your needs:

It uses some MVVM binding, so no events are actually used. If you don't know about MVVM, try to duckduckgo it a bit.

First some XAML, the default main page:

<Page
    x:Class="App6.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App6"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DataContext="{d:DesignInstance local:ViewModel, IsDesignTimeCreatable=True}">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ListView ItemsSource="{Binding Items}" 
                  DataFetchSize="1" 
                  IncrementalLoadingTrigger="Edge" 
                  IncrementalLoadingThreshold="5">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Text}"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>

Note the ItemsSource="{Binding Items}" DataFetchSize="1" IncrementalLoadingTrigger="Edge" IncrementalLoadingThreshold="5"

  1. ItemSource will bind to the items collection, its used in the item template
  2. DataFetchSize, the amount to fetch when the end is reached: in PAGES. (confused me for a moment)
  3. IncrementalLoadingTrigger, see msdn
  4. IncrementalLoadingThreshold, see msdn

Then..., the code:

First a custom observable collection: Here is also your load routine:

public class IncrementalLoadingCollection : ObservableCollection<Item>, ISupportIncrementalLoading
{
    uint x = 0; //just for the example
    public bool HasMoreItems { get { return x < 10000; } } //maximum

    //the count is the number requested
    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
    {
        return AsyncInfo.Run(async cancelToken =>
        {
            //here you need to do your loading
            for (var c = x; c < x + count; c++)
            {
                //add your newly loaded item to the collection
                Add(new Item()
                {
                    Text = c.ToString()
                });
            }

            x += count;
            //return the actual number of items loaded (here it's just maxed)
            return new LoadMoreItemsResult { Count = count };
        });
    }
}

We are using a new Item class, so lets define it:

//the type which is being used to display the data
//you could extend it to use images and stuff
public class Item
{
    public string Text { get; set; }
}

Lets create a viewmodel:

public class ViewModel
{
    public ViewModel()
    {
        Items = new IncrementalLoadingCollection();
    }
    //using the custom collection: these are your loaded items
    public IncrementalLoadingCollection Items { get; set; }
}

Wrap it up in the code behind: we use the data context:

/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        DataContext= new ViewModel(); //using a viewmodel as data context           
    }
}

More info can be found here