New to Telerik UI for Xamarin? Download free 30-day trial

Multi-Level Grouping

This article provides an overview on how you could enable multi-level grouping in RadListView.

Before proceeding please go through Grouping Overview topic.

First, let's create the following business object:

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

The next example demonstrates how RadListView could be bound to a collection of City objects and grouped hieararchically by Continent and Country.

To accomplish the task, create a ViewModel class as shown below:

public class ViewModel
{
    public ObservableCollection<City> Cities { get; set; }

    public ViewModel()
    {
        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" }
         };
    }
}

Then, in order to visualize the hierarchical relation between groups, add a custom GroupHeaderTemplate (of type DataTemplate) to the Resources of your page:

<ResourceDictionary>
    <local:LevelToMarginConverter x:Key="LevelToMarginConverter" />
    <DataTemplate x:Key="ListViewItemTemplate">
        <telerikListView:ListViewTemplateCell>
            <telerikListView:ListViewTemplateCell.View>
                <Grid Padding="50, 0, 0, 0" BackgroundColor="#F1F2F5">
                    <Label Text="{Binding Name}" TextColor="#6F6F70" FontSize="Small" />
                </Grid>
            </telerikListView:ListViewTemplateCell.View>
        </telerikListView:ListViewTemplateCell>
    </DataTemplate>
    <DataTemplate x:Key="ListViewMultiLevelGroupHeaderTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Label Text="&#x25B8;" Margin="{Binding Level, Converter={StaticResource LevelToMarginConverter}}" 
                   TextColor="DarkGray" FontSize="Medium">
                <Label.Triggers>
                    <DataTrigger TargetType="Label" Binding="{Binding IsExpanded}" Value="True">
                        <Setter Property="Text" Value="&#x25BE;" />
                    </DataTrigger>
                </Label.Triggers>
            </Label>
            <Label Margin="0, 12, 0, 6" Text="{Binding }" Grid.Column="1" TextColor="DarkGray" FontSize="Medium" HorizontalOptions="Start" />
        </Grid>
    </DataTemplate>
    <telerikListView:ListViewGroupStyle x:Key="ListViewGroupHeaderStyle" BackgroundColor="Transparent" />
</ResourceDictionary>

where LevelToMarginConverter just calculates the margin of each group header according to its Level:

<ResourceDictionary>
    <local:LevelToMarginConverter x:Key="LevelToMarginConverter" />
    <DataTemplate x:Key="ListViewItemTemplate">
        <telerikListView:ListViewTemplateCell>
            <telerikListView:ListViewTemplateCell.View>
                <Grid Padding="50, 0, 0, 0" BackgroundColor="#F1F2F5">
                    <Label Text="{Binding Name}" TextColor="#6F6F70" FontSize="Small" />
                </Grid>
            </telerikListView:ListViewTemplateCell.View>
        </telerikListView:ListViewTemplateCell>
    </DataTemplate>
    <DataTemplate x:Key="ListViewMultiLevelGroupHeaderTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Label Text="&#x25B8;" Margin="{Binding Level, Converter={StaticResource LevelToMarginConverter}}" 
                   TextColor="DarkGray" FontSize="Medium">
                <Label.Triggers>
                    <DataTrigger TargetType="Label" Binding="{Binding IsExpanded}" Value="True">
                        <Setter Property="Text" Value="&#x25BE;" />
                    </DataTrigger>
                </Label.Triggers>
            </Label>
            <Label Margin="0, 12, 0, 6" Text="{Binding }" Grid.Column="1" TextColor="DarkGray" FontSize="Medium" HorizontalOptions="Start" />
        </Grid>
    </DataTemplate>
    <telerikListView:ListViewGroupStyle x:Key="ListViewGroupHeaderStyle" BackgroundColor="Transparent" />
</ResourceDictionary>

Lastly, add the RadListView definition with two PropertyGroupDescriptors as shown in the next snippet:

<telerikDataControls:RadListView x:Name="listView" ItemsSource="{Binding Cities}"
                                 ItemTemplate="{StaticResource ListViewItemTemplate}"
                                 GroupHeaderTemplate="{StaticResource ListViewMultiLevelGroupHeaderTemplate}"
                                 GroupHeaderStyle="{StaticResource ListViewGroupHeaderStyle}">
    <telerikDataControls:RadListView.GroupDescriptors>
        <telerikListView:PropertyGroupDescriptor PropertyName="Continent"/>
        <telerikListView:PropertyGroupDescriptor PropertyName="Country"/>
    </telerikDataControls:RadListView.GroupDescriptors>      
</telerikDataControls:RadListView>

Here is the final result:

See Also

In this article