Если визуальное представление, используемое для вывода данных в ListView, повторяется и применяется в отдельных частях приложения, то мы можем вынести это представление в отдельный класс, который унаследован от ViewCell.
Например, необходимо, чтобы каждая ячейка отображала данные абстрактного товара и была наподобие ImageCell, только с возможностью устанавливать высоту и ширину изображения.
Для этого добавим в проект новый класс CustomCell, который будет представлять отдельную ячейку:
public class CustomCell : ViewCell { Label titleLabel, detailLabel; Image image; public CustomCell() { titleLabel = new Label { FontSize = 18 }; detailLabel = new Label(); image = new Image(); StackLayout cell = new StackLayout { Orientation = StackOrientation.Horizontal, Margin = new Thickness(5, 8) }; StackLayout titleDetailLayout = new StackLayout { Margin = 5 }; titleDetailLayout.Children.Add(titleLabel); titleDetailLayout.Children.Add(detailLabel); cell.Children.Add(image); cell.Children.Add(titleDetailLayout); View = cell; } public static readonly BindableProperty TitleProperty = BindableProperty.Create("Title", typeof(string), typeof(CustomCell), ""); public static readonly BindableProperty ImagePathProperty = BindableProperty.Create("ImagePath", typeof(ImageSource), typeof(CustomCell), null); public static readonly BindableProperty ImageWidthProperty = BindableProperty.Create("ImageWidth", typeof(int), typeof(CustomCell), 100); public static readonly BindableProperty ImageHeightProperty = BindableProperty.Create("ImageHeight", typeof(int), typeof(CustomCell), 100); public static readonly BindableProperty DetailProperty = BindableProperty.Create("Detail", typeof(string), typeof(CustomCell), ""); public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public int ImageWidth { get { return (int)GetValue(ImageWidthProperty); } set { SetValue(ImageWidthProperty, value); } } public int ImageHeight { get { return (int)GetValue(ImageHeightProperty); } set { SetValue(ImageHeightProperty, value); } } public ImageSource ImagePath { get { return (ImageSource)GetValue(ImagePathProperty); } set { SetValue(ImagePathProperty, value); } } public string Detail { get { return (string)GetValue(DetailProperty); } set { SetValue(DetailProperty, value); } } protected override void OnBindingContextChanged() { base.OnBindingContextChanged(); if (BindingContext != null) { titleLabel.Text = Title; detailLabel.Text = Detail; image.Source = ImagePath; image.WidthRequest = ImageWidth; image.HeightRequest = ImageHeight; } } }
Ячейка будет состоять из двух элементов Label, расположенных вертикально, и элемента Image.
Для получения данных извне и привязки данных к элементам Label и Image определены свойства BindableProperty.
Для обработки изменения контекста привязки переопределен метод OnBindingContextChanged
.
Пусть данные описываются следующим классом Language, который представляет язык программирования:
class Language { public string Name { get; set; } = ""; public string Description { get; set; } = ""; public string ImagePath { get; set; } = ""; }
Добавим в проект в папку Resources/Images несколько изображений, которые представляют логотипы языков программирования:
Определим в коде C# страницу, которая будет выводить список:
namespace HelloApp; class StartPage : ContentPage { public StartPage() { ListView listView = new ListView(); // определяем источник данных listView.ItemsSource = new List<Language> { new Language {Name="C#", ImagePath="csharp_sm.jpg", Description = "Последняя версия C# 11" }, new Language {Name="C++", ImagePath="cpp_sm.jpg", Description = "Последняя версия C++23" }, new Language {Name="Java", ImagePath="java_sm.jpg", Description = "Последняя версия Java 19" }, new Language {Name="Python", ImagePath="python_sm.png", Description = "Последняя версия Python 3.11" }, }; // определяем шаблон данных listView.ItemTemplate = new DataTemplate(() => { CustomCell customCell = new CustomCell { ImageHeight = 40, ImageWidth = 40 }; customCell.SetBinding(CustomCell.TitleProperty, "Name"); customCell.SetBinding(CustomCell.DetailProperty, "Description"); customCell.SetBinding(CustomCell.ImagePathProperty, "ImagePath"); return customCell; }); Label header = new Label { FontSize = 18, Text = "Языки программирования" }; Content = new StackLayout { Children = { header, listView }, Padding=7}; } }
Использование CustomCell в 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"> <ContentPage.Resources> <ResourceDictionary> <x:Array x:Key="langs" Type="{x:Type local:Language}"> <local:Language Name="C#" ImagePath="csharp_sm.jpg" Description="Последняя версия C# 11" /> <local:Language Name="C++" ImagePath="cpp_sm.jpg" Description="Последняя версия C++23" /> <local:Language Name="Java" ImagePath="java_sm.jpg" Description="Последняя версия Java 19" /> <local:Language Name="Python" ImagePath="python_sm.png" Description="Последняя версия Python 3.11" /> </x:Array> </ResourceDictionary> </ContentPage.Resources> <StackLayout Padding="7"> <Label Text="Языки программирования" FontSize="18" /> <ListView ItemsSource="{StaticResource langs}"> <ListView.ItemTemplate> <DataTemplate> <local:CustomCell ImagePath="{Binding ImagePath}" ImageWidth="40" ImageHeight="40" Title="{Binding Name}" Detail="{Binding Description}"/> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage>