Элемент ListView в Xamarin поддерживает возможности группировки. Рассмотрим, как мы можем сгруппировать элементы в списке
Для группировки в начале добавим в проект вспомогательный класс, который назовем Grouping:
using System.Collections.Generic; 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) { Name = name; foreach (T item in items) Items.Add(item); } } }
Класс Grouping типизирован двумя параметрами. Параметр K представляет тип ключа группы, который будет храниться в свойстве Name
.
А параметр T представляет тип объектов, которые будут храниться в коллекции Items. Это свойство-коллекция унаследовано от базового класса ObservableCollection.
А в конструкторе мы получаем все необходимые данные.
В качестве объектов возьмем опять же класс Phone:
public class Phone { public string Title { get; set; } public string Company { get; set; } public int Price { get; set; } }
В коде страницы MainPage создадим список групп:
using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Xamarin.Forms; namespace HelloApp { public partial class MainPage : ContentPage { // список групп, к которым идет привязка public ObservableCollection<Grouping<string, Phone>> PhoneGroups { get; set; } public MainPage() { InitializeComponent(); // начальные данные var phones = new List<Phone> { new Phone {Title="Galaxy S8", Company="Samsung", Price=60000 }, new Phone {Title="Galaxy S7 Edge", Company="Samsung", Price=50000 }, new Phone {Title="Huawei P10", Company="Huawei", Price=10000 }, new Phone {Title="Huawe Mate 8", Company="Huawei", Price=29000 }, new Phone {Title="Mi6", Company="Xiaomi", Price=55000 }, new Phone {Title="iPhone 7", Company="Apple", Price=38000 }, new Phone {Title="iPhone 6S", Company="Apple", Price=50000 } }; // получаем группы var groups = phones.GroupBy(p => p.Company).Select(g => new Grouping<string, Phone>(g.Key, g)); // передаем группы в PhoneGroups PhoneGroups = new ObservableCollection<Grouping<string, Phone>>(groups); this.BindingContext = this; } } }
В конструкторе переменная phones
определяет общие данные, по которым создается коллекция групп в виде свойства PhoneGroups
. Группировка
в данном случае идет по свойству Company объекта Phone.
А в коде xaml у MainPage пропишем выражения привязки:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="HelloApp.MainPage"> <StackLayout> <ListView x:Name="phonesList" HasUnevenRows="True" GroupDisplayBinding="{Binding Name}" ItemsSource="{Binding PhoneGroups}" IsGroupingEnabled="True"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout> <Label Text="{Binding Title}" /> <Label Text="{Binding Price}" /> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage>
Привязка ListView здесь идет к свойству PhoneGroups, которое содержит группы. Установка свойства IsGroupingEnabled="True"
добавляет в ListView поддержку групп.
С помошью свойства GroupDisplayBinding можно задать то значение, которое будет отображаться для каждой группы. В нашем случае идет привязка к имени группы, которое представляет критерий группировки.
И после запуска приложения все данные в списке будут сгруппированы по компаниям:
Однако по умолчанию заголовки групп выглядят не очень хорошо, мало отличимы от основного содержимого элементов. И в этом случае мы можем настроить шаблон отображения заголовков групп. Для этого изменим разметку xaml:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:HelloApp;assembly=HelloApp" x:Class="HelloApp.MainPage"> <StackLayout> <ListView x:Name="phonesList" HasUnevenRows="True" ItemsSource="{Binding PhoneGroups}" IsGroupingEnabled="True"> <ListView.GroupHeaderTemplate> <DataTemplate> <ViewCell Height="30"> <StackLayout> <Label Text="{Binding Name}" FontSize="Large" /> </StackLayout> </ViewCell> </DataTemplate> </ListView.GroupHeaderTemplate> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout> <Label Text="{Binding Title}" /> <Label Text="{Binding Price}" /> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage>
Свойство GroupHeaderTemplate позволяет в корне изменить отображение заголовка, определив ему свой шаблон DataTemplate: