ISupportIncrementalLoading loads more items than required

In my UWP, I have ListViewone that populates gradually using an interface ISupportIncrementalLoadingfor infinite scrolling.

This list is on the page PageX, and as soon as I go to this page, it closes ListView.

This something works, and sometimes not. The problem occurs when I go to PageX, it LoadMoreItemsAsyncis called more than once (for the first time, only for further scrolling it works fine).

Here is my code:

    public class ItemsToShow : ObservableCollection<SearchResultViewModel>, ISupportIncrementalLoading
{
    private SearchResponse ResponseObject { get; set; } = new SearchResponse();
    private MetadataReply Metadata { get; set; } = new MetadataReply();
    SearchResultViewModel viewModel = null;


    public bool HasMoreItems
    {
        get
        {
            if ((string.IsNullOrEmpty(SomeStaticClass.NextPageToken) && !SomeStaticClass.IsFirstRequest) || SomeStaticClass.StopIncrementalLoading)
                return false;

            if(SomeStaticClass.IsFirstRequest)
            {
                using (var db = new DbContext())
                {
                    var json = db.UpdateResponse.First(r => r.LanguageId == DataStore.Language).JsonResponse;
                    Metadata = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateApiResponse>(json).response.metadata.reply;
                }

                var returnObject = SomeStaticClass.SearchResponse;
                ResponseObject = returnObject.response;               
            }
            else
            {
                var returnObject = new SearchApiCall().CallSearchApiAsync(
                            SomeStaticClass.QueryString,
                            SomeStaticClass.NextPageToken,
                            SomeStaticClass.Filters).Result;
                ResponseObject = returnObject.response;
            }

           return ResponseObject.documents.Count > 0;     
        }
    }

    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
    {
        CoreDispatcher coreDispatcher = Window.Current.Dispatcher;
        if (SomeStaticClass.IsFirstRequest) SomeStaticClass.Facet = ResponseObject.facets;

        return Task.Run<LoadMoreItemsResult>(async () =>
        {

            await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                foreach (var item in ResponseObject.documents)
                {
                    this.Add(new SearchResultViewModel { .... });
                }
            });

            SomeStaticClass.IsFirstRequest = false;
            SomeStaticClass.NextPageToken = ResponseObject.pageToken;

            await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                SearchResultPage.searchResultPage.FilterButton.Visibility = Visibility.Visible;
            });

            return new LoadMoreItemsResult() { Count = count };

        }).AsAsyncOperation<LoadMoreItemsResult>();
    }
}

My ListView:

<ListView Name="SearchResultListView"
    SelectionMode="Single"
    IsItemClickEnabled="True"
    ItemClick="SearchResultListView_ItemClick">

    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>               
        </Style>
    </ListView.ItemContainerStyle>

    <ListView.ItemTemplate>
        <DataTemplate x:DataType="ViewModels:SomeViewModel">

            <Grid Style="{StaticResource SomeStyle}">
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>

                <TextBlock Text="{x:Bind qqq}/>                

                <StackPanel  Grid.Row="1">
                    <TextBlock Text="{x:Bind xxx}"/>
                    <TextBlock Text="{x:Bind yyy}"/>
                </StackPanel>

                <StackPanel Grid.Row="2">                               
                    <TextBlock Text="{x:Bind aaa}"/>
                    <TextBlock Text="{x:Bind bbb}"  />
                </StackPanel>

                <TextBlock Text="{x:Bind EducationalLevel}"/

                <StackPanel Grid.Row="4">                        
                    <TextBlock Text="{x:Bind Language}"/>                        
                    <Image Source="{x:Bind ccc}"/>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Code behind page with this ListView:

    public sealed partial class SearchResultPage
    {   
        public static SearchResultPage searchResultPage { get; private set; }
        private SearchResultParameterWrapper ReceivedParameter { get; set; } = new SearchResultParameterWrapper();        

        public SearchResultPage()
        {        
            InitializeComponent();          
            NavigationCacheMode = NavigationCacheMode.Enabled;
            searchResultPage = this;
        }

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {                       
            base.OnNavigatedTo(e);

            if (e.NavigationMode != NavigationMode.Back) FilterButton.Visibility = Visibility.Collapsed;

            SomeStaticClass.IsFirstRequest = true;
            SomeStaticClass.Filters = new FilterParametersWrapper();           


            ReceivedParameter = (SearchResultParameterWrapper)e.Parameter;
            if (ReceivedParameter != null)
            {
                SomeStaticClass.QueryString = ReceivedParameter.QueryString;
                SomeStaticClass.Filters = ReceivedParameter.Filters;
                SomeStaticClass.RestoreOldFilters = ReceivedParameter.RestoreOldFilters;

                if(SomeStaticClass.IsFirstRequest)
                    await HandleNoResult(ReceivedParameter);
            }


        }

        private async Task HandleNoResult(SearchResultParameterWrapper parameter)
        {
            if (!ApiStore.IsConnected())
            {
                Toast.ShowToast(MainPage.mainPage.ViewModel._APP_check_network, ToastRow);
                return;
            }

            MyProgressRing.IsActive = true;

            SearchResultListView.ItemsSource = null;
            SearchResultListView.Items.ToList().Clear();
            SearchResponse responseObject = null;
            SearchApiResponse apiResponse = null;
            try
            {               
                SomeStaticClass.StopIncrementalLoading = true;

                SomeStaticClass.SearchResponse = await new SearchApiCall().CallSearchApiAsync(parameter.QueryString, null, parameter.Filters);
                apiResponse = SomeStaticClass.SearchResponse;
                responseObject = apiResponse.response;

                if (responseObject.documents.Count <= 0)
                {                  
                    NoResultsTextBlock.Visibility = Visibility.Visible;
                    FilterButton.Visibility = Visibility.Collapsed;
                    return;
                }
                else
                { 
                    SearchResultListView.ItemsSource = new ItemsToShow();
                    SomeStaticClass.StopIncrementalLoading = false;
                }
            }
            catch
            {

            }
            finally
            {
                MyProgressRing.IsActive = false;
            }
        }        


        public bool Reload() { return Reload(null); }
        private bool Reload(object param)
        {
            System.Type type = Frame.CurrentSourcePageType;
            if (Frame.BackStack.Any())
            {                
                param = ReceivedParameter;
            }
            try { return Frame.Navigate(type, param); }
            finally { Frame.BackStack.Remove(Frame.BackStack.Last()); }
        }
    }

EDIT

I am updating my code. The same problem remains and another problem arises, i.e. The page is sometimes blank (after displaying elements for one or two seconds):

public class ItemsToShow : ObservableCollection<SearchResultViewModel>, ISupportIncrementalLoading
{
    private SearchResponse ResponseObject { get; set; } = new SearchResponse();       
    private bool hasMoreItems { get; set; } = true;

    public bool HasMoreItems
    {
        set
        {
            hasMoreItems = value;
        }
        get
        {
            if (SomeCondition) return false;
            return hasMoreItems;               
        }
    }

    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
    {
        CoreDispatcher coreDispatcher = Window.Current.Dispatcher;

        Task.Delay(10);
        return Task.Run<LoadMoreItemsResult>(async () =>
        {
            if (IsFirstRequest)
            {
                HasMoreItems = string.IsNullOrEmpty(ResponseObject.someProperty) ? false : true;
                IsFirstRequest = false;
            }
            else
            {   
                ResponseObject = await new SomeClass().SomeMethod();                 
                HasMoreItems = string.IsNullOrEmpty(ResponseObject.someProperty) ? false : true;
            }

            await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                foreach (var item in ResponseObject.documents)
                {             
                    this.Add(PrepareViewModel(item));
                }
            });

            await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                SearchResultPage.searchResultPage.FilterButton.Visibility = Visibility.Visible;
            });                            
            return new LoadMoreItemsResult() { Count = count };               
        }).AsAsyncOperation<LoadMoreItemsResult>();
    }
}
+4
1

, . , .

, , , , .

ISupportIncrementalLoading.LoadMoreItemsAsync , . , , ListView.

, , ListView , , , . , LoadMoreItemsAsync . , LoadMoreItemsAsync, , count 1 .

, , , . , , , .

UWP Community Toolkit, , - -

private bool? _firstLoadJustPassed;
private async Task<LoadMoreItemsResult> LoadMoreItemsAsync(uint count, CancellationToken cancellationToken)
{
    if (_firstLoadJustPassed == true)
    {
        _firstLoadJustPassed = false;
        return new LoadMoreItemsResult { Count = 0 };
    }

    uint resultCount = 0;
    _cancellationToken = cancellationToken;

    try
    {
        if (!_cancellationToken.IsCancellationRequested)
        {
            IEnumerable<IType> data = null;
            try
            {
                IsLoading = true;
                data = await LoadDataAsync(_cancellationToken);
            }
            catch (OperationCanceledException)
            {
                // The operation has been canceled using the Cancellation Token.
            }
            catch (Exception ex) when (OnError != null)
            {
                OnError.Invoke(ex);
            }

            if (data != null && data.Any() && !_cancellationToken.IsCancellationRequested)
            {
                resultCount = (uint)data.Count();

                foreach (var item in data)
                {
                    Add(item);
                }

                if (!_firstLoadJustPassed.HasValue)
                {
                    _firstLoadJustPassed = true;
                }
            }
            else
            {
                HasMoreItems = false;
            }
        }
    }
    finally
    {
        IsLoading = false;

        if (_refreshOnLoad)
        {
            _refreshOnLoad = false;
            await RefreshAsync();
        }
    }

    return new LoadMoreItemsResult { Count = resultCount };
}

, , , , , IncrementalLoadingCollection , .

+3

Source: https://habr.com/ru/post/1680099/


All Articles