CollectionView with RemainingItemsThreshold and groups

Enrico Rossini 236 Reputation points
2025-09-30T20:07:44.4666667+00:00

In my .NET 9 MAUI application, I have a CollectionView and the view model in the page passes the values via an ObservableCollection.

    public class WordGroup : List<Word>
    {
        public string Name { get; private set; }

        public WordGroup(string name, List<Word> words) : base(words)
        {
            Name = name;
        }
    }

    [ObservableProperty] 
    private ObservableCollection<WordGroup>? _wordGroups;

The CollectionView is defined like this:

	<CollectionView
		x:Name="cvWords"
		Grid.Row="1"
		IsGrouped="True"
		ItemsSource="{Binding WordGroups}"
		RemainingItemsThreshold="5"
		RemainingItemsThresholdReached="cvWords_RemainingItemsThresholdReached"
		SelectionMode="Single"
		VerticalOptions="FillAndExpand"> 

When the threshold is reached, the app runs this function

    private async void cvWords_RemainingItemsThresholdReached(object sender, 
        EventArgs e)
    {
        if (BindingContext is DictionaryWordsListViewModel vm)
        {
            await vm.ReadMoreWords();
        }
    }

ReadMoreWords reads from the APIs a pageSize items based on the next page and adds the records to the Words that is defined as List<Word>. So, in the Words I have all the previous items plus the new one. Then, I have to group Words using this function

    public void GroupWords()
    {
        if (Words != null && Words.Count == 0)
        {
            WordGroups = new ObservableCollection<WordGroup>();
            return;
        }

        if (IsGroupedByLetter)
            WordGroups = Words?.ToObservableGroups();
        else
            WordGroups = Words?.ToObservableGroups(Enums.GroupFor.WordType);
    }

The problem is that every time I add new elements and group them, the CollectionView jumps at the beginning. Here is what happens.

enter image description here

I tried to amend this function

    private async void cvWords_RemainingItemsThresholdReached(object sender, 
        EventArgs e)
    {
        if (BindingContext is DictionaryWordsListViewModel vm)
        {
            await vm.ReadMoreWords();

            cvWords.ScrollTo(vm.WordGroups?.LastOrDefault(), 
                             position: ScrollToPosition.End, animate: false);
        }
    }

with no results. Also, I tried to change the GroupWords function by adding the following code.

    foreach (var newGroup in list)
    {
        var existingGroup = WordGroups.FirstOrDefault(g => g.Name == newGroup.Name);

        if (existingGroup == null)
        {
            WordGroups.Add(newGroup);
        }
        else
        {
            foreach (var word in newGroup)
            {
                if (!existingGroup.Any(w => w.ID == word.ID))
                    existingGroup.Add(word);
            }
        }
    }

In this case, the application crashes when I add the second newGroup to the WordGroups. How can I change the code to have a usable CollectionView with groups and RemainingItemsThreshold to make an efficient render?

Developer technologies | .NET | .NET MAUI
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Michael Le (WICLOUD CORPORATION) 3,935 Reputation points Microsoft External Staff Moderator
    2025-10-01T03:12:28.18+00:00

    Hello Enrico,

    Thank you for reaching out.

    Based on the information you've provided, it looks like you are completely replacing the WordGroups collection every time you load more items.

    // ...
    if (IsGroupedByLetter)
        WordGroups = Words?.ToObservableGroups(); // This creates a new collection
    else
        WordGroups = Words?.ToObservableGroups(Enums.GroupFor.WordType); // So does this
    

    When you assign a new ObservableCollection to the ItemsSource of the CollectionView, the view has no choice but to discard its current state (including the scroll position) and render the new data from scratch.

    In this case, I think it would be better to append the new items rather than replacing the entire collection.

    Your second attempt has an issue: your WordGroup class inherits from List<Word>. The List<T> class does not notify the UI when items are added or removed. When you call existingGroup.Add(word), the CollectionView is unaware that the group's content has changed.

    To fix this, you should change WordGroup to be an ObservableCollection<Word> itself, or a class that contains an ObservableCollection<Word>.

    You could consider this approach:

    1. In ReadMoreWords, after fetching the new words from your API, group only the new items.
    2. Iterate through these newly created groups.
    3. For each new group:
      • Check if a group with the same Name already exists in your main WordGroups collection.
      • If it does, add the new words to that existing group's collection of words.
      • If it does not, add the entire new group to the WordGroups collection.

    I hope this helps. Let me know if you have any further questions or need additional assistance.

    If my suggestions resolve your issue, please consider marking this response as final.

    Thank you.

    1 person found this answer helpful.

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.