Класс CollectionView предназначен для вывода списков на сложных макетах и предоставляет более гибкую и производительную альтернативу по сравнению с ListView
.
Отличия от ListView:
CollectionView имеет гибкую модель компоновки, позволяя отображать данные вертикально или горизонтально, в виде списка или таблицы.
CollectionView поддерживает выбор как одного, так и нескольких элементов.
CollectionView не имеет концепции ячеек, как ListView. Вместо этого для определения внешнего вида каждого элемента используется шаблон данных.
CollectionView автоматически использует виртуализацию, которая предоставляется нативными нижележащими элементами используемой операционной системы
CollectionView обладает меньшим API. Многие свойства и события из ListView отсутствуют в CollectionView.
CollectionView не поддерживает разделители элементов.
CollectionView сгенерирует исключение, если его свойство ItemsSource
будет обновлено вне потока пользовательского интерфейса.
Для определения источника данных применяется свойство ItemsSource, которое в качестве значения принимает коллекцию IEnumerable
.
Например, определим следующую страницу в коде C#
class StartPage : ContentPage { public StartPage() { CollectionView collectionView = new CollectionView { Margin=5 }; collectionView.ItemsSource = new string[] { "Tom", "Sam", "Bob", "Alice", "Kate" }; Content = collectionView; } }
За установку шаблона отображения данных отвечает свойство ItemsTemplate, которое представляет объект DataTemplate и которое принимает в качестве значения одноименный объект DataTemplate. Простейший пример:
class StartPage : ContentPage { public StartPage() { CollectionView collectionView = new CollectionView { Margin=5 }; // определяем источник данных collectionView.ItemsSource = new string[] { "Tom", "Sam", "Bob", "Alice", "Kate" }; // определяем шаблон данных collectionView.ItemTemplate = new DataTemplate(() => { var personLbl = new Label { FontSize = 16, TextColor = Color.FromArgb("#1565C0") }; personLbl.SetBinding(Label.TextProperty, new Binding("BindingContext", source: RelativeBindingSource.Self)); return personLbl; }); Content = collectionView; } }
Конструктор DataTemplate
принимает делегат, который возвращает объект-шаблон элемента списка.
В данном случае в качестве шаблона элемента выступает метка personLbl, для которой устанавливаются цвет текста и высота шрифта. Поскольку по умолчанию для объекта-шаблона
в качестве контекста привязки (свойство BindingContext
) используется отображаемый элемент списка, то для отображения текста в метке используется привязка к
свойству BindingContext
этой же метки (new Binding("BindingContext", source: RelativeBindingSource.Self)
Аналогичный пример в 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" > <CollectionView> <CollectionView.ItemsSource> <x:Array Type="{x:Type x:String}"> <x:String>Tom</x:String> <x:String>Sam</x:String> <x:String>Bob</x:String> <x:String>Alice</x:String> <x:String>Kate</x:String> </x:Array> </CollectionView.ItemsSource> <CollectionView.ItemTemplate> <DataTemplate> <Label Text="{Binding}" FontSize="16" TextColor="#1565C0" /> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </ContentPage>
Как правило, объекты списока представляют более комплексные по структуре данные. Например, пусть у нас есть класс Person, который представляет пользователя:
public class Person { public string Name { get; set; } = ""; public int Age { get; set; } public string Company { get; set; } = ""; }
В коде C# определим страницу, которая выводит в CollectionView список пользователей:
namespace HelloApp; class StartPage : ContentPage { public StartPage() { CollectionView collectionView = new CollectionView(); // определяем источник данных collectionView.ItemsSource = new List<Person> { new Person { Name="Tom", Age=38, Company ="Microsoft" }, new Person { Name="Sam", Age=25, Company ="Google" }, new Person { Name="Bob", Age=42, Company ="JetBrains" }, new Person { Name="Alice", Age=33, Company ="Microsoft" }, new Person { Name="Kate", Age=29, Company ="Google" }, new Person { Name="Amelia", Age=35, Company ="JetBrains" }, }; // определяем шаблон данных collectionView.ItemTemplate = new DataTemplate(() => { var nameLabel = new Label { FontSize = 20, TextColor = Color.FromArgb("#006064"), Margin = 10 }; nameLabel.SetBinding(Label.TextProperty, "Name"); var ageLabel = new Label(); ageLabel.SetBinding(Label.TextProperty, new Binding { Path = "Age", StringFormat = "Возраст: {0}" }); var companyLabel = new Label(); companyLabel.SetBinding(Label.TextProperty, "Company"); return new StackLayout { Children = { nameLabel, ageLabel, companyLabel }, Margin = new Thickness(15, 10) }; }); Content = collectionView ; } }
В данном случае в качестве шаблона данных выступает объект StackLayout. И для каждого элемента создается свой StackLayout с тремя метками Label, каждая из которых привязана к определенному свойству объекта Person. На Windows это будет выглядеть так:
Аналогичный пример в 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" xmlns:local="clr-namespace:HelloApp"> <CollectionView> <CollectionView.ItemsSource> <x:Array Type="{x:Type local:Person}"> <local:Person Name="Tom" Age="38" Company="Microsoft"/> <local:Person Name="Sam" Age="25" Company="Google"/> <local:Person Name="Bob" Age="42" Company="JetBrains"/> <local:Person Name="Alice" Age="33" Company="Microsoft"/> <local:Person Name="Kate" Age="29" Company="Google"/> <local:Person Name="Amelia" Age="35" Company="JetBrains" /> </x:Array> </CollectionView.ItemsSource> <CollectionView.ItemTemplate> <DataTemplate> <StackLayout Margin="8"> <Label Text="{Binding Name}" FontSize = "20" TextColor = "#006064" Margin="10" /> <Label Text="{Binding Age, StringFormat='Возраст: {0}'}" /> <Label Text="{Binding Company}" /> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </ContentPage>
С помощью свойств Header и Footer у 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" xmlns:local="clr-namespace:HelloApp"> <CollectionView Header="Список пользователей" Footer="Данные актуальны на январь 2023г."> <CollectionView.ItemsSource> <x:Array Type="{x:Type local:Person}"> <local:Person Name="Tom" Company="Microsoft" /> <local:Person Name="Bob" Company="Google" /> <local:Person Name="Sam" Company="JetBrains" /> <local:Person Name="Alice" Company="Microsoft" /> <local:Person Name="Kate" Company="Google" /> </x:Array> </CollectionView.ItemsSource> <CollectionView.ItemTemplate> <DataTemplate> <StackLayout Padding="8"> <Label Text="{Binding Name}" FontSize="18" TextColor="#006064" /> <Label Text="{Binding Company}" /> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </ContentPage>
Но в данном случае мы увидим небольшие надписи в начале и в конце списка:
Установка в коде C#:
CollectionView collectionView = new CollectionView(); collectionView.Header = "Список пользователей"; collectionView.Footer = "Январь 2023 г.";
Также CollectionView позволяет задать шаблон для их отображения:
<?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"> <CollectionView> <CollectionView.ItemsSource> <x:Array Type="{x:Type local:Person}"> <local:Person Name="Tom" Company="Microsoft" /> <local:Person Name="Bob" Company="Google" /> <local:Person Name="Sam" Company="JetBrains" /> <local:Person Name="Alice" Company="Microsoft" /> <local:Person Name="Kate" Company="Google" /> </x:Array> </CollectionView.ItemsSource> <CollectionView.Header> <Label Text= "Список пользователей" FontSize="18" FontAttributes="Bold" /> </CollectionView.Header> <CollectionView.Footer> <Label Text= "Январь 2023г." FontSize="14" FontAttributes="Italic" /> </CollectionView.Footer> <CollectionView.ItemTemplate> <DataTemplate> <StackLayout Padding="8"> <Label Text="{Binding Name}" FontSize="18" TextColor="#006064" /> <Label Text="{Binding Company}" /> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </ContentPage>