Collections (mid and large lists)
Do not Add in a loop for mid or large lists. AddRange raises one CollectionChanged Reset. Large lists must also virtualize — ItemsRepeater / ListView virtualization. The framework will not pretend 100,000 realized rows are fine.
var items = new ObservableRangeCollection<Product>();
items.AddRange(page); // one CollectionChanged Reset
items.ReplaceRange(next);Pagination and search
PagedCollection<T> / DelegatePagedCollection<T> own load-more, refresh, and retry — not a live inbox. SnapshotCollection<T> loads once in InitializeAsync; later LoadAsync calls are no-ops unless force is true. SearchQuery.Text binds to a TextBox or MvvmSearch; filter from CommittedText after debounce.
public sealed class InboxViewModel : ViewModel
{
public SnapshotCollection<Conversation> Inbox { get; }
public SearchQuery Search { get; } = new();
public InboxViewModel(IInbox catalog)
{
Inbox = new SnapshotCollection<Conversation>(
ct => catalog.ListAsync(Search.CommittedText, ct));
}
protected override Task InitializeAsync(CancellationToken cancellationToken) =>
Inbox.LoadAsync(cancellationToken: cancellationToken);
}
await Products.RefreshAsync(ct);
await Products.LoadMoreAsync(ct);