Multi-Level Grouping
This article provides an overview on how you could enable multi-level grouping in the ListView.
Before proceeding, go through the Grouping Overview topic.
-
Create the following business object:
public class City { public string Continent { get; set; } public string Name { get; set; } public string Country { get; set; } }
-
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" } }; } }
-
To visualize the hierarchical relation between groups, add a custom
GroupHeaderTemplate
(of typeDataTemplate
) to the Resources of your page:<ResourceDictionary> <multiLevelGrouping: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="▸" Margin="{Binding Level, Converter={StaticResource LevelToMarginConverter}}" TextColor="DarkGray" FontSize="Medium"> <Label.Triggers> <DataTrigger TargetType="Label" Binding="{Binding IsExpanded}" Value="True"> <Setter Property="Text" Value="▾" /> </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>
-
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; } }
-
Add the
RadListView
definition with twoPropertyGroupDescriptors
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.BindingContext> <local:GroupingViewModel/> </telerikDataControls:RadListView.BindingContext> <telerikDataControls:RadListView.GroupDescriptors> <telerikListView:PropertyGroupDescriptor PropertyName="Continent"/> <telerikListView:PropertyGroupDescriptor PropertyName="Country"/> </telerikDataControls:RadListView.GroupDescriptors> </telerikDataControls:RadListView>
-
Add the namespaces:
xmlns:telerikDataControls="clr-namespace:Telerik.XamarinForms.DataControls;assembly=Telerik.Maui.Controls.Compatibility" xmlns:telerikListView="clr-namespace:Telerik.XamarinForms.DataControls.ListView;assembly=Telerik.Maui.Controls.Compatibility"
The following image shows the final result.