Довольно часто, при работе над приложением .NET MAUI нам требуется сделать привязку не к отдельному объекту и его свойству, а сразу к списку объектов. Например, чтобы вывести на экран список пользователей, проектов, задач и так далее. На данный момент мы уже знаем про такой элемент управления, как Picker. В этой части мы рассмотрим то, как можно заполнить этот элемент списком объектов, а также раздеремся с шаблонами данных на примере еще одного элемента — CollectionView.
Заполнение Picker списком объектов
Теперь, когда мы изучили основы привязки данных в .NET MAUI, можно рассмотреть ещё один вариант работы с элементом Picker и заполнить список его элементов, используя объекты своего класса. Для примера, воспользуемся классом Project, который мы рассматривали в предыдущей части. Вот как выглядит наш класс:
public class Project : INotifyPropertyChanged
{
string name = "";
bool isActive = false;
double cost = 0;
public string Name
{
get => name;
set
{
if (name != value)
{
name = value;
OnPropertyChanged();
}
}
}
public bool IsActive
{
get => isActive;
set
{
if (isActive != value)
{
isActive = value;
OnPropertyChanged();
}
}
}
public double Cost
{
get => cost;
set
{
if (cost != value)
{
cost = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}
Используем объекты этого класса для заполнения списка. Добавим на страницу MainPage следующий ресурс:
<ContentPage.Resources>
<ResourceDictionary>
<x:Array x:Key="Projects" Type="{x:Type local:Project}">
<local:Project Name="Проект №1" IsActive="True" Cost="120"/>
<local:Project Name="Проект №2" IsActive="True" Cost="130"/>
<local:Project Name="Проект №3" IsActive="True" Cost="140"/>
<local:Project Name="Проект №4" IsActive="True" Cost="150"/>
<local:Project Name="Проект №5" IsActive="True" Cost="160"/>
</x:Array>
</ResourceDictionary>
</ContentPage.Resources>
Зная основы привязки, мы можем легко привязать этот массив объектов к списку Picker.ItemSource, например так:
<VerticalStackLayout BindingContext="{StaticResource Projects}">
<Picker ItemsSource="{StaticResource Projects}" ItemDisplayBinding="{Binding Path=Name}"/>
</VerticalStackLayout>
Здесь мы передаем в ItemSource массив и дополнительно привязываем свойство Picker.ItemDisplayBinding к свойству Name класса Project. Теперь наш список будет таким:
Более того, мы можем ещё сократить этот код. Так как контекст привязки определен в родительском контейнере и это, по сути, всё тот же массив элементов, то мы можем привязаться к нему используя расширение разметки Binding вот так:
<VerticalStackLayout BindingContext="{StaticResource Projects}">
<Picker ItemsSource="{Binding}" ItemDisplayBinding="{Binding Path=Name}"/>
</VerticalStackLayout>
Результат работы приложение будет точно таким же, как и на рисунке выше.
Шаблоны данных (DataTemplate)
Рассмотрим ещё один пример работы с коллекциями объектов на примере пока ещё не изученного нами элемента управления — CollectionView. Элемент CollectionView предназначен для отображения списка однотипных данных. Этот элемент имеет достаточно гибкую систему различных настроек и, как следствие, содержит множество свойств для работы. Однако мы сосредоточимся на главном и разберемся с тем как заполнить CollectionView коллекцией объектов своего класса. Для работы нам потребуется всего два свойства CollectionView:
| Свойство | Тип | Описание |
Items |
IEnumerable |
Коллекция объектов, которые необходимо отобразить в списке |
ItemTemplate |
DataTemplate |
Шаблон данных |
Элемент CollectionView предназначен для отображения данных любых объектов и изначально, если передать в свойстве ItemSource коллекцию объектов, то CollectionView будет пытаться отобразить эти данные, используя метод ToString() класса. Например, вернемся к нашему приложению и добавим в него новый элемент управления:
<VerticalStackLayout BindingContext="{StaticResource Projects}">
<Picker ItemsSource="{Binding}" ItemDisplayBinding="{Binding Path=Name}"/>
<CollectionView ItemsSource="{Binding}"/>
</VerticalStackLayout>
В результате, мы увидим вот такой список объектов:
Можно было бы переопределить в нашем классе метод ToString() и выводить в список необходимые нам строки, но это не самый лучший вариант так как нам может потребоваться использовать свойства объектов в различных вариациях в разных элементах управления. Здесь нам и потребуется второе свойство — ItemTemplate
Перепишем код элемента следующим образом:
<CollectionView ItemsSource="{Binding}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="{x:Type local:Project}">
<Border Background="LightGray" Padding="5">
<VerticalStackLayout>
<Label Text="{Binding Name}"/>
<CheckBox IsChecked="{Binding IsActive}"/>
<Label Text="{Binding Cost}"/>
</VerticalStackLayout>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
В свойстве ItemTemplate мы указываем шаблон данных, то есть то, как наш объект должен отображаться в списке. Свойство x:DataType у DataTemplate указывает объект какого типа будет участвовать при формировании шаблона:
<DataTemplate x:DataType="{x:Type local:Project}">
Далее, внутри DataTemplate мы указываем как визуально будет отображаться объект — здесь мы можем использовать любые элементы управления, применять к ним стили, задействовать другие ресурсы и так далее. Стоит обратить внимание на то как производится привязка к свойствам объекта. Так как тип объекта известен, а коллекция таких объектов уже привязана к свойству ItemSource, то мы используем при привязке только имена свойств:
<Label Text="{Binding Name}"/>
<CheckBox IsChecked="{Binding IsActive}"/>
<Label Text="{Binding Cost}"/>
В итоге, в приложении будет сформирован вот такой список проектов:
Итого
Используя привязку в .NET MAUI мы можем привязывать к элементам управления коллекции объектов. Для отображения данных сложных объектов удобно пользоваться шаблонами данных, определяя свойство ItemTemplate типа DataTemplate у элемента управления.
