5

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

Stefan
  • 17,448
  • 11
  • 60
  • 79
ace
  • 225
  • 4
  • 18
  • 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 Aug 08 '18 at 06:47
  • @Stefan `lstSuggestions_PointerEntered` is called whenever the pointer is moved to listview area/section. It just captures whether the pointer is in listview UI area – ace Aug 08 '18 at 06:49
  • 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 Aug 08 '18 at 06:55
  • @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 too – ace Aug 08 '18 at 06:57
  • 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? ] (https://stackoverflow.com/a/37430977/8024811) however it doesn't helped in my case – ace Aug 08 '18 at 06:59
  • Well, I havn't done this in a while but, normally I would use a more MVVM approach, use an `ItemSource` for the list view and trigger the load on the visibility of the last item. I have done this before with Xamarin and WP8, so I would think for UWP it would be something similar. ... I'll try to wrap someting up. – Stefan Aug 08 '18 at 07:10
  • @Stefan thanks for the suggestion, can you please explain it using any code, as i am completely new to UWP. I have several ways to do so, but everyt other way is failed – ace Aug 08 '18 at 07:12
  • i want to do something like, when listview scrolled to last item i will again call to `public async void GetData(string Id, string limit)` function & will pass limit as next 100 items, & bind it to the listview – ace Aug 08 '18 at 07:14

1 Answers1

7

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 MVVM bindings so no typical UI events are 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

Stefan
  • 17,448
  • 11
  • 60
  • 79
  • Hey, thanks for your valuable inputs, i will just go through changes suggested by you. & will let you know in sometime – ace Aug 08 '18 at 08:54
  • Where the comment is: `//here you need to do your loading`, you can delete the for loop and use your own logic to fill the collection – Stefan Aug 08 '18 at 09:15
  • API is return in such a way that it can load only 100 items, as there is a vast amount of data, thats why i am passing limit parameter in my code, as on reaching end of the list it will call an API to load next 100 – ace Aug 08 '18 at 09:18
  • can i simply do `lstSuggestions.add(new Item(name, id))` as`lstSuggestions` having dependency on other functionalities. I am using `lstSuggestions` to achieve the other functionalities. if i make changes suggested by you, then in that case i won't be able to use `lstSuggestions` – ace Aug 08 '18 at 09:28
  • Moreover i need to have `X:Name=lstSuggestions` in my .xaml file – ace Aug 08 '18 at 09:30
  • Hi, how can i implement searchBox functionality for the same? I have done something like this : private void search_Suggestions(object sender, SearchBoxQueryChangedEventArgs e) { if (loadedList != null) { lstSuggestions.ItemsSource = loadedList.Where(a => a.Name.ToUpper().Contains(searchSuggestions.QueryText.ToUpper())); } } – ace Aug 17 '18 at 06:30
  • 1
    Hi, it's best to ask a new question, possibly refer to this one, you'll get full attention and the best chance of getting your question answered ;-) – Stefan Aug 17 '18 at 08:37
  • hope you will give valuable suggestion for this question : [SearchBox in lazy loaded ListView](https://stackoverflow.com/questions/51961610/how-to-implement-searchbox-functionality-in-incrementallylazy-loaded-listview) – ace Aug 22 '18 at 07:27
  • Hi Stefan, great example. Do you have any experience with variable sizes in virtualized items? `VariableSizedWrapGrid` seems to be not supported with `ISupportIncrementalLoading` but perhaps something else? Or this combined with grouping? I am trying to group by date. As far as I found grouping is not possible, so I try to create items that are at full with of a `GridView`. Any experience in that? – CularBytes Nov 01 '19 at 13:18
  • Sorry, I am unfaliar with those controls. Maybe you can post a question here on so. – Stefan Nov 01 '19 at 14:52