New to Telerik UI for .NET MAUI? Start a free 30-day trial

The RadListView control is now obsolete and will be removed in the future. Use the RadCollectionView control instead. The RadCollectionView is a complete, ground-up rewrite of the ListView. The RadCollectionView offers improved performance, enhanced features, and a modernized approach to managing lists of data. The RadCollectionView incorporates all of the ListView's key features. More about the differences between both components and how to migrate to the new RadCollectionView is available in the Migrating the Telerik .NET MAUI RadListView to RadCollectionView article.

.NET MAUI ListView Multi-Level Grouping

This article provides an overview on how you can enable multi-level grouping in the ListView.

Before proceeding, go through the Grouping Overview topic.

1. Create the following business object:

public class City
{
    public string Continent { get; set; }
    public string Name { get; set; }
    public string Country { get; set; }
}

2. Create a ViewModel class as shown below:

public class GroupingViewModel : NotifyPropertyChangedBase
{
    public ObservableCollection<City> Cities { get; set; }

    public GroupingViewModel()
    {
        this.Cities = new ObservableCollection<City>()
        {
            new City() { Name = "Barcelona", Country = "Spain", Continent = "Europe"},
            new City() { Name = "Madrid", Country = "Spain", Continent = "Europe" },
            new City() { Name = "Rome", Country = "Italy", Continent = "Europe" },
            new City() { Name = "Florence", Country = "Italy", Continent = "Europe" },
            new City() { Name = "London", Country = "England", Continent = "Europe" },
            new City() { Name = "Manchester", Country = "England", Continent = "Europe"},
            new City() { Name = "New York", Country = "USA", Continent = "North America" },
            new City() { Name = "Boston", Country = "USA",  Continent = "North America" }
         };
    }
}

3. To visualize the hierarchical relation between groups, add a custom GroupHeaderTemplate (of type DataTemplate) to the Resources of your page:

<ResourceDictionary>
    <multiLevelGrouping:LevelToMarginConverter x:Key="LevelToMarginConverter" />
    <DataTemplate x:Key="ListViewItemTemplate">
        <telerik:ListViewTemplateCell>
            <telerik:ListViewTemplateCell.View>
                <Grid HeightRequest="40" Padding="48, 0, 0, 0">
                    <Label Text="{Binding Name}" TextColor="#6F6F70" FontSize="Small" VerticalOptions="Center" />
                </Grid>
            </telerik:ListViewTemplateCell.View>
        </telerik:ListViewTemplateCell>
    </DataTemplate>
    <DataTemplate x:Key="ListViewMultiLevelGroupHeaderTemplate">
        <Grid HeightRequest="40" BackgroundColor="#F1F2F5">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Label Text="&#xE806;" Margin="{Binding Level, Converter={StaticResource LevelToMarginConverter}}" 
                   TextColor="DarkGray" FontFamily="TelerikFontExamples" FontSize="Medium" VerticalOptions="Center">
                <Label.Triggers>
                    <DataTrigger TargetType="Label" Binding="{Binding IsExpanded}" Value="True">
                        <Setter Property="Text" Value="&#xE80D;" />
                    </DataTrigger>
                </Label.Triggers>
            </Label>
            <Label Margin="8, 0, 0, 0" Text="{Binding }" Grid.Column="1" TextColor="DarkGray" FontSize="Medium" VerticalOptions="Center" />
        </Grid>
    </DataTemplate>
    <telerik:ListViewGroupStyle x:Key="ListViewGroupHeaderStyle" BackgroundColor="Transparent" />
</ResourceDictionary>

4. The LevelToMarginConverter calculates the margin of each group header according to its Level:

public class LevelToMarginConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            var level = (int)value;
            return new Thickness(((level - 1) * 20) + 8, 12, 0, 6);
        }
        else return value;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}

5. Add the RadListView definition with two PropertyGroupDescriptors as shown in the next snippet:

<telerik:RadListView x:Name="listView" ItemsSource="{Binding Cities}"
                     ItemTemplate="{StaticResource ListViewItemTemplate}"
                     GroupHeaderTemplate="{StaticResource ListViewMultiLevelGroupHeaderTemplate}"
                     GroupHeaderStyle="{StaticResource ListViewGroupHeaderStyle}">
    <telerik:RadListView.BindingContext>
        <local:GroupingViewModel/>
    </telerik:RadListView.BindingContext>
    <telerik:RadListView.GroupDescriptors>
        <telerik:ListViewPropertyGroupDescriptor PropertyName="Continent"/>
        <telerik:ListViewPropertyGroupDescriptor PropertyName="Country"/>
    </telerik:RadListView.GroupDescriptors>
</telerik:RadListView>

6. Include the telerik namespace:

xmlns:telerik="http://schemas.telerik.com/2022/xaml/maui" 

The following image shows the final result.

.NET MAUI ListView Multi-Level Grouping

See Also

In this article