Why are the same items added to my CollectionView repeatedly?
Here's what happens exactly:
On every load (on scroll) I want to load 5 more items into my CollectionView, but this is what happens:
Task.Delay(1000)
the items 1,2,3,4,5 are added, then 1,2,3,4,5 again before adding 6,7,8,9,10 etc.DisplayAlert()
items are added without repitition for some reason. Obviously it's not a solution.It looks like the delay that the display alert causes, gives the script time to process the next items. Obviously I do not want to display an alert but the collection behaves as expected when I use it.
This is my CollectionView with "posts":
<CollectionView ItemsSource="{Binding Posts}"
ItemTemplate="{StaticResource CommunityItemTemplateSelector}"
RemainingItemsThresholdReachedCommand="{Binding PopulateCommand}"
RemainingItemsThreshold="0">
<!-- Using DataTemplates to populate -->
</CollectionView>
This is the ViewModel populating it:
Populates the collection of items with new "posts" when the page appears or you hit the bottom of the CollectionView
.
private CommunityService communityService { get; set; }
private int start = 0;
private int limit = 5;
private List<CommunityItem> posts { get; set; } = new();
public ObservableRangeCollection<CommunityItem> Posts { get; private set; } = new();
public Command OnAppearingCommand { get; private set; }
public Command PopulateCommand { get; private set; }
public CommunityViewModel(CommunityService communityService)
{
this.communityService = communityService;
OnAppearingCommand = new Command(Appearing);
PopulateCommand = new Command(Populate);
}
private void Appearing()
{
Posts.Clear();
Populate();
}
private async void Populate()
{
posts.Clear();
await Task.Delay(250);
posts = await communityService.GetPosts(start, limit);
start += limit;
if (posts.Count > 0)
Posts.AddRange(posts);
}
This is the API getting new "posts":
It's not the API, this has been tested with Postman and works fine!
public class CommunityService : BaseService
{
public List<CommunityItem> List = new();
public async Task<List<CommunityItem>> GetPosts(int start, int limit)
{
string range = "&start=" + start + "&limit=" + limit;
try
{
var response = await http.GetAsync(this.uri + "/post" + range + this.key);
if (response.IsSuccessStatusCode && response.Content is not null)
List = await response.Content.ReadFromJsonAsync<List<CommunityItem>>();
// Somewhat solving the problem:
await Task.Delay(1000);
// Solving it completely for some reason, but shows an alert:
await Application.Current.MainPage.DisplayAlert("Debug", "Waiting", "OK");
}
catch (Exception e)
{
// Debug
}
return List;
}
}
Well, according to Panagiotis Kanavos's comment, as a wiki answer:
it's because of
async void
, which is a bug in itself. There's no way to awaitasync void
calls so it's possible the command "completes" immediately and the component keeps asking for new data repeatedly, beforecommunityService.GetPosts
has a chance to complete and update the counts. Either make your code synchronous or use the AsyncRelayCommand from the MAUI Community Toolkit.
Switching to AsyncRelayCommand can solve the problem to a certain extent.