Search code examples
c#xamlmauimaui-community-toolkitmaui-collectionview

Grouped CollectionView header text not working when using ObservableGroupedCollection


I need a grouped collection view and I would like to bind it to an ObservableGroupedCollection because I am wanting to update the data and my updates to be reflected in the UI. In order to do this I have adapted the example found here
https://github.com/jfversluis/MauiCollectionViewGroupingSample but I am having a problem with the collection view headers not rendering the data.

To demonstrate my problem I have created a .net 8 maui app and referenced the nuget package CommunityToolkit.Mvvm version 8.2.2.

Here is my viewmodel

using CommunityToolkit.Mvvm.Collections;
using CommunityToolkit.Mvvm.ComponentModel;

namespace TestGroupedCollectionView;

public partial class PageViewModel: ObservableObject
{
    public ObservableGroupedCollection<AnimalGroup, Animal> Animals { get; set; } = [];


    public PageViewModel()
    {

        var bearGroup = new AnimalGroup
        {
            GroupName = "Bears"
        };

        var bears = new List<Animal>
        {
            new Animal
            {
                Name = "American Black Bear"    
            },
            new Animal
            {
                Name = "Asian Black Bear"     
            }
        };

        Animals.Add(new ObservableGroup<AnimalGroup, Animal>(bearGroup, bears));

        var monkeys = new List<Animal>
        {
            new Animal
            {
                Name = "Baboon"             
            },
            new Animal
            {
                Name = "Capuchin Monkey",             
            },
            new Animal
            {
                Name = "Blue Monkey"            
            },
        };

        var monkeyGroup = new AnimalGroup
        {
            GroupName = "Monkeys"
        };

        Animals.Add(new ObservableGroup<AnimalGroup, Animal>(monkeyGroup, monkeys));  
    }
}

Here is the animal class

public class Animal
{
    public string Name { get; set; } = "";
}

Here is the animal group class

public class AnimalGroup 
{
    public string GroupName { get; set; } = "";
}

Here is the code behind of my page


namespace TestGroupedCollectionView;
public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        BindingContext = new PageViewModel();
    }  
}

And here is my xaml code


<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:viewmodeldto="clr-namespace:TestGroupedCollectionView" 
             x:Class="TestGroupedCollectionView.MainPage">

    <CollectionView ItemsSource="{Binding Animals}" IsGrouped="True">
        <CollectionView.GroupHeaderTemplate>
            <DataTemplate>
                <Label FontSize="18" FontAttributes="Bold" BackgroundColor="Gray" Text="{Binding GroupName}" />
            </DataTemplate>
        </CollectionView.GroupHeaderTemplate>
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <VerticalStackLayout>
                    <Label
                       Text="{Binding Name}"/>        
                </VerticalStackLayout>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

</ContentPage>

I have run the code on an emulator, i.e. an Android Studio Pixel 5 and the output you get is:

American Black Bear
Asian Black Bear

Baboon
Capuchin Monkey
Blue Monkey

In other words the group header template is being rendered but the Name text is being left blank. What I am trying to get instead is the following output:
Bears
American Black Bear
Asian Black Bear
Monkeys
Baboon
Capuchin Monkey
Blue Monkey

which as you can see includes the 2 headers, bears and monkeys.

I have tried to add a Datatype like this

<DataTemplate x:DataType="viewmodeldto:AnimalGroup">
                <Label FontSize="18" FontAttributes="Bold" BackgroundColor="Gray" Text="{Binding GroupName}" />
</DataTemplate>

But it doesn't make any difference.


Solution

  • To display grouped data in a CollectionView, you may refer to official docs Display grouped data in a CollectionView.

    You could make some changes for AnimalGroup,

    public class AnimalGroup : ObservableCollection<Animal>
    {
        public string Name { get; private set; }
    
        public AnimalGroup(string name, ObservableCollection<Animal> animals) : base(animals)
        {
            Name = name;
        }
    }
    

    And in your viewModel, use ObservableCollection instead of List.

    public partial class PageViewModel : ObservableObject
    {
    
        //public ObservableCollection<AnimalGroup> Animals { get; set; } = new ObservableCollection<AnimalGroup>();
    
        [ObservableProperty]
        public ObservableCollection<AnimalGroup> animals  = new ObservableCollection<AnimalGroup>();
        public PageViewModel()
        {
            Animals.Add(new AnimalGroup("Bears", new ObservableCollection<Animal>
                {
                    new Animal
                    {
                        Name = "American Black Bear",
                    },
                    new Animal
                    {
                        Name = "Asian Black Bear",
                    }
    
                }));
    

    Then if you want to add some new Animal, just try something like,

    Animals[0].Add(new Animal { Name = "My Bear" });
    

    This will also update the UI.

    Hope it helps!