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>();
}
}