ListView представляет очень мощный элемет управления .NET MAUI, который позволяет отображать список объектов и при этом кастомизировать их отображение.
ListView связывается с набором данных через свойство ItemsSource, которое принимает объект IEnumerable<T>
.
Определим в коде C# объект ListView, который выводит массив строк:
namespace HelloApp; class StartPage : ContentPage { public StartPage() { Label header = new Label{ Text = "Список пользователей" }; // данные для ListView string[] people = new string[] { "Tom", "Bob", "Sam", "Alice" }; ListView listView = new ListView(); // определяем источник данных listView.ItemsSource = people; Content = new StackLayout { Children = { header, listView }, Padding=7}; } }
При выводе каждого объекта ListView по умолчанию вызывает для него метод ToString()
, поэтому мы увидим строковое отображение объекта.
Аналогичный массив в 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> <Label Text="Список пользователей"/> <ListView> <ListView.ItemsSource> <x:Array Type="{x:Type x:String}"> <x:String>Tom</x:String> <x:String>Bob</x:String> <x:String>Sam</x:String> <x:String>Alice</x:String> </x:Array> </ListView.ItemsSource> </ListView> </StackLayout> </ContentPage>
Здесь напрямую определяется массив строк для свойства ListView.ItemsSource
. Однако обычно данные определяются вне, например, в виде ресурса:
<?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"> <ContentPage.Resources> <ResourceDictionary> <x:Array x:Key="people" Type="{x:Type x:String}"> <x:String>Tomas</x:String> <x:String>Bob</x:String> <x:String>Sam</x:String> <x:String>Alice</x:String> </x:Array> </ResourceDictionary> </ContentPage.Resources> <StackLayout> <Label Text="Список пользователей"/> <ListView ItemsSource="{StaticResource people}" /> </StackLayout> </ContentPage>
Нередко источник данных для ListView определяется в коде C#. И в этом случае мы можем использовать привязку к источнику данных. Например, в коде C# у страницы MainPage определим список строк, к которому будет производиться привязка:
namespace HelloApp; public partial class MainPage : ContentPage { public List<string> Users { get; set; } public MainPage() { InitializeComponent(); Users = new List<string> { "Tom", "Bob", "Sam", "Alice" }; BindingContext = this; } }
Стоит отметить, что источник данных определен как публичное свойство Users. Другой важный момент - установка контекста привязки страницы: BindingContext = this;
.
Таким образом, в XAML мы можем обратиться ко всем публичным свойствам страницы.
В коде 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> <Label Text="Список пользователей"/> <ListView ItemsSource="{Binding Users}" /> </StackLayout> </ContentPage>
Когда пользователь нажимает на элемент списка, он выделяется, а у ListView срабатывают два события: ItemTapped и ItemSelected. Между ними есть различия. Так, повторное нажатие на один и тот же элемент не вызовет повторного события ItemSelected, так как элемент остается выбанным. А вот событие ItemTapped будет срабатывать именно столько раз сколько пользователь нажал на него, даже повторно. Также событие ItemSelected будет вызвано, если с элемента будет снято выделение.
Обработаем выделение элемента. Для этого определим следующий код в MainPage.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 Padding="7"> <Label x:Name="selected"/> <ListView x:Name="usersList" ItemSelected="usersList_ItemSelected" /> </StackLayout> </ContentPage>
А в файле кода MainPage.xaml.cs определим источник данных и обработчик события ItemSelected:
namespace HelloApp; public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); usersList.ItemsSource = new List<string> { "Tom", "Bob", "Sam", "Alice" }; } private void usersList_ItemSelected(object sender, SelectedItemChangedEventArgs e) { selected.Text = $"Выбрано: {e.SelectedItem}"; } }
При выборе элемента мы можем получить выбранный элемент через свойство SelectedItem объекта SelectedItemChangedEventArgs
, который передается в качестве параметра.
Поскольку список содержит массив строк, то каждый его элемент представляет строку, которую мы можем получить с помощью метода e.SelectedItem.ToString()
.
Похожим образом можно обработать событие ItemTapped. Определим в 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 Padding="7"> <Label x:Name="selected"/> <ListView x:Name="usersList" ItemTapped="usersList_ItemTapped" /> </StackLayout> </ContentPage>
А в файле кода MainPage.xaml.cs определим источник данных и обработчик события ItemTapped:
namespace HelloApp; public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); usersList.ItemsSource = new List<string> { "Tom", "Bob", "Sam", "Alice" }; } private void usersList_ItemTapped(object sender, ItemTappedEventArgs e) { selected.Text = $"Нажато: {e.Item}"; } }
Обработчики событий нажатия и выбора элементы хороши, если нам надо выполнить некоторую логику, связанную с этим элементом. Однако если нам надо просто вывести выбранный элемент в метку, то мы можем просто установить привязку к выбранному в ListView элементу. В примере выше мы вполне могли бы обойтись без обработки события и просто установить привязку элемента Label к выбранному объекту списка. Выбранный элемент в ListView хранится в свойстве SelectItem:
<?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"> <ContentPage.Resources> <ResourceDictionary> <x:Array x:Key="users" Type="{x:Type x:String}"> <x:String>Tom</x:String> <x:String>Bob</x:String> <x:String>Sam</x:String> <x:String>Alice</x:String> </x:Array> </ResourceDictionary> </ContentPage.Resources> <StackLayout Padding="7"> <Label Text="{Binding Source={Reference usersList}, Path=SelectedItem}" /> <ListView x:Name="usersList" ItemsSource="{StaticResource users}" /> </StackLayout> </ContentPage>
В данном случае свойство Text метки привязано к свойству SelectedItem элемента usersList. И при изменении выбранного элемента в ListView метка также изменить свой текст.
Установка привязке в коде C#:
namespace HelloApp; class StartPage : ContentPage { public StartPage() { Label header = new Label(); ListView usersList = new ListView(); // определяем источник данных usersList.ItemsSource = new string[] { "Tomas", "Bob", "Sam", "Alice" }; // установка привязки к SelectedItem header.SetBinding(Label.TextProperty, new Binding { Source= usersList, Path ="SelectedItem" }); Content = new StackLayout { Children = { header, usersList }, Padding=7}; } }
Свойство RowHeight позволяет задать высоту строки в ListView. Но действовать оно будет только в том случае, если другое свойство в ListView - HasUnevenRows равно false (значение по умолчанию).
Установка в XAML:
<ListView RowHeight="100" >
В коде C#:
listView.RowHeight = 100;