Элемент CollectionView поддерживает группировку данных. Для этого класс предоставляет ряд свойств:
IsGrouped: при значении true
будет применяться группировка. Значение по умолчанию - false
.
GroupHeaderTemplate: шаблон DataTemplate
для отображения заголовка группы.
GroupFooterTemplate: шаблон DataTemplate
для отображения футтера группы.
Рассмотрим, как мы можем сгруппировать элементы в списке.
Допустим, наши данные представлены классом User:
public class Person { public string Name { get; set; } = ""; public string Company { get; set; } = ""; }
Класс Person определяет два свойства: для имени и для компании пользователя. Так как компания может совпадать у разных пользователей, то можно по этому признаку сгруппировать объекты Person.
Для группировки в начале добавим в проект вспомогательный класс, который назовем Grouping:
using System.Collections.ObjectModel; namespace HelloApp; public class Grouping<K, T> : ObservableCollection<T> { public K Name { get; private set; } public Grouping(K name, IEnumerable<T> items) : base(items) { Name = name; } }
Класс Grouping типизирован двумя параметрами. Параметр K представляет тип ключа группы, который будет храниться в свойстве Name
.
А параметр T представляет тип объектов, которые будут храниться в коллекции Items. Это свойство-коллекция унаследовано от базового класса ObservableCollection.
А в конструкторе мы получаем все необходимые данные.
В коде страницы MainPage.xaml.cs создадим список групп:
using System.Collections.ObjectModel; namespace HelloApp; public partial class MainPage : ContentPage { // список групп, к которым идет привязка public ObservableCollection<Grouping<string, Person>> PeopleGroups { get; set; } public MainPage() { InitializeComponent(); // начальные данные var people = new List<Person> { new Person {Name="Tom", Company="Microsoft" }, new Person {Name="Sam", Company="Google" }, new Person {Name="Alice", Company="Microsoft" }, new Person {Name="Bob", Company="JetBrains" }, new Person {Name="Kate", Company="Google" }, }; // получаем группы var groups = people.GroupBy(p => p.Company).Select(g => new Grouping<string, Person>(g.Key, g)); // передаем группы в PeopleGroups PeopleGroups = new ObservableCollection<Grouping<string, Person>>(groups); BindingContext = this; } }
В конструкторе переменная people
определяет общие данные, по которым создается коллекция групп в виде свойства PeopleGroups
. Группировка
в данном случае идет по свойству Company объекта User.
А в коде xaml у MainPage пропишем выражения привязки:
<?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" x:Class="HelloApp.MainPage" > <StackLayout> <CollectionView ItemsSource="{Binding PeopleGroups}" IsGrouped="True"> <CollectionView.ItemTemplate> <DataTemplate> <StackLayout Padding="8"> <Label Text="{Binding Name}" FontSize="20" TextColor="#006064" /> <Label Text="{Binding Company}" /> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </StackLayout> </ContentPage>
Здесь CollectionView привязан к PeopleGroups, которое содержит группы. Установка свойства IsGrouped="True"
добавляет в CollectionView поддержку групп.
И после запуска приложения все данные в списке будут сгруппированы по компаниям:
По умолчанию заголовки групп не отображаются, поэтому посмотрим, как их настроить. Например, отобразим в качестве заголовка название группы. Для этого изменим разметку xaml:
<?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" x:Class="HelloApp.MainPage" > <StackLayout> <CollectionView ItemsSource="{Binding PeopleGroups}" IsGrouped="True"> <CollectionView.GroupHeaderTemplate> <DataTemplate> <Label Text="{Binding Name}" FontSize="22" TextColor="#006064" /> </DataTemplate> </CollectionView.GroupHeaderTemplate> <CollectionView.ItemTemplate> <DataTemplate> <StackLayout Padding="8"> <Label Text="{Binding Name}" FontSize="18" /> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </StackLayout> </ContentPage>
Свойство GroupHeaderTemplate получает шаблон DataTemplate, где мы можем настроить отображение. В данном случае заголовок будет представлять элемент Label, который привязан к названию группы:
Подобным образом можно настроить шаблон для отображения футера с помощью свойства GroupFooterTemplate:
<?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" x:Class="HelloApp.MainPage" xmlns:local="clr-namespace:HelloApp"> <StackLayout> <CollectionView ItemsSource="{Binding PeopleGroups}" IsGrouped="True"> <CollectionView.GroupHeaderTemplate> <DataTemplate> <Label Text="{Binding Name}" FontSize="22" TextColor="#006064" /> </DataTemplate> </CollectionView.GroupHeaderTemplate> <CollectionView.GroupFooterTemplate> <DataTemplate> <Label Text="{Binding Count, StringFormat='Total employees: {0:D}'}" Margin="0,0,0,10" /> </DataTemplate> </CollectionView.GroupFooterTemplate> <CollectionView.ItemTemplate> <DataTemplate> <StackLayout Padding="8"> <Label Text="{Binding Name}" FontSize="18" /> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </StackLayout> </ContentPage>
Футер также представляет метку, текст которой привязан к свойству Count
(поскольку коллекция PeopleGroups представляет тип ObservableCollection, то она имеет
свойство Count
, которое возвращает количество элементов).