ListView

Browse sample. Обзор примера

Многоплатформенный пользовательский интерфейс приложения .NET (.NET MAUI) ListView отображает прокручиваемый вертикальный список элементов данных, доступных для выбора. При ListView управлении внешним видом списка внешний вид каждого элемента в списке определяется тем DataTemplate , что используется Cell для отображения элементов. .NET MAUI включает типы ячеек для отображения сочетаний текста и изображений, а также можно определить пользовательские ячейки, отображающие любое нужное содержимое. ListView также включает поддержку отображения верхних и нижних колонтитулов, группированных данных, извлечения и обновления элементов контекстного меню.

Класс ListView является производным от ItemsView<Cell> класса, от которого он наследует следующие свойства:

  • ItemsSourceIEnumerableТип , указывает коллекцию отображаемых элементов и имеет значение nullпо умолчанию.
  • ItemTemplateDataTemplateТип , указывает шаблон, применяемый к каждому элементу в коллекции отображаемых элементов.

ListView определяет следующие свойства:

  • FooterobjectТип , указывает строку или представление, которое будет отображаться в конце списка.
  • FooterTemplate, тип DataTemplate, указывает DataTemplate , что используется для форматирования Footer.
  • GroupHeaderTemplateDataTemplateТип , определяет DataTemplate используемый для определения внешнего вида заголовка каждой группы. Это свойство является взаимоисключающим с свойством GroupDisplayBinding . Поэтому при установке этого свойства задано значение GroupDisplayBindingnull.
  • HasUnevenRowsboolТип , указывает, могут ли элементы в списке иметь строки разных высот. Значение по умолчанию этого свойства равно false.
  • HeaderobjectТип , указывает строку или представление, которое будет отображаться в начале списка.
  • HeaderTemplate, тип DataTemplate, указывает DataTemplate , что используется для форматирования Header.
  • HorizontalScrollBarVisibility, тип ScrollBarVisibility, указывает, когда горизонтальная полоса прокрутки будет видна.
  • IsGroupedEnabledboolТип , указывает, должны ли базовые данные отображаться в группах. Значение по умолчанию этого свойства равно false.
  • IsPullToRefreshEnabledboolТип , указывает, может ли пользователь провести пальцем вниз, чтобы привести ListView к обновлению данных. Значение по умолчанию этого свойства равно false.
  • IsRefreshingboolТип , указывает, обновляется ли в ListView данный момент обновление. Значение по умолчанию этого свойства равно false.
  • RefreshCommandICommandТип , представляет команду, которая будет выполняться при активации обновления.
  • RefreshControlColorColorТип , определяет цвет визуализации обновления, отображаемой во время обновления.
  • RowHeight, тип int, определяет высоту каждой строки, когда HasUnevenRows это false.
  • SelectedItemobjectТип , представляет текущий выбранный элемент в элементе ListView.
  • SelectionModeListViewSelectionModeТип , указывает, могут ли элементы быть выбраны в ListView или нет. Значение по умолчанию этого свойства равно Single.
  • SeparatorColorColorТип , определяет цвет панели, разделяющей элементы в списке.
  • SeparatorVisibility, типа SeparatorVisibility, определяет, отображаются ли разделители между элементами.
  • VerticalScrollBarVisibilityТип , указывает, когда вертикальная полоса прокрутки ScrollBarVisibilityбудет видна.

Все эти свойства поддерживаются BindableProperty объектами, что означает, что они могут быть целевыми объектами привязки данных и стилем.

Кроме того, ListView определяет следующие свойства, которые не поддерживаются BindableProperty объектами:

  • GroupDisplayBinding(тип BindingBase) привязка, используемая для отображения заголовка группы. Это свойство является взаимоисключающим с свойством GroupHeaderTemplate . Поэтому при установке этого свойства задано значение GroupHeaderTemplatenull.
  • GroupShortNameBindingBindingBaseТип , привязка для имени, отображаемая в сгруппированных списках переходов.
  • CachingStrategy, тип ListViewCachingStrategy, определяет стратегию повторного использования ячейки ListView. Это свойство доступно только для чтения.

ListView определяет следующие события:

  • ItemAppearing, который возникает при добавлении визуального представления элемента в визуальный макет ListViewэлемента. Объект ItemVisibilityEventArgs , который сопровождает это событие, определяет Item и Index свойства.
  • ItemDisappearing, который возникает при удалении визуального представления элемента из визуального макета ListViewэлемента. Объект ItemVisibilityEventArgs , который сопровождает это событие, определяет Item и Index свойства.
  • ItemSelected, который возникает при выборе нового элемента в списке. Объект SelectedItemChangedEventArgs , который сопровождает это событие, определяет SelectedItem и SelectedItemIndex свойства.
  • ItemTapped, который вызывается при нажатии элемента в элементе ListView . ОбъектItemTappedEventArgs, который сопровождает это событие, определяет Groupи ItemItemIndex свойства.
  • Refreshing, который возникает при активации ListViewоперации извлечения для обновления.
  • Scrolled, . Объект ScrolledEventArgs , который сопровождает это событие, определяет ScrollX и ScrollY свойства.
  • ScrollToRequested . ОбъектScrollToRequestedEventArgs, сопровождающий это событие, определяет Element, Mode, Position, и ScrollXScrollYShouldAnimate свойства.

Заполнение ListView данными

A ListView заполняется данными, задав свойству ItemsSource любую коллекцию, которая реализует IEnumerable.

Важно!

ListView Если требуется обновить элементы при добавлении, удалении или изменении в базовой коллекции, базовая коллекция должна быть IEnumerable коллекцией, которая отправляет уведомления об изменении свойств, напримерObservableCollection.

ListView можно заполнить данными с помощью привязки данных для привязки его ItemsSource свойства к IEnumerable коллекции. В XAML это достигается с расширением Binding разметки:

<ListView ItemsSource="{Binding Monkeys}" />

Эквивалентный код на C# выглядит так:

ListView listView = new ListView();
listView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

В этом примере ItemsSource данные свойств привязываются к Monkeys свойству подключенного представления.

Примечание.

Скомпилированные привязки можно включить для повышения производительности привязки данных в приложениях .NET MAUI. Дополнительные сведения см. в разделе "Скомпилированные привязки".

Дополнительные сведения о привязке данных см. в разделе "Привязка данных".

Определение внешнего вида элемента

Внешний вид каждого элемента в ListView объекте можно определить, задав ItemTemplate для свойства значение DataTemplate:

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid Padding="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Image Grid.RowSpan="2"
                           Source="{Binding ImageUrl}"
                           Aspect="AspectFill"
                           HeightRequest="60"
                           WidthRequest="60" />
                    <Label Grid.Column="1"
                           Text="{Binding Name}"
                           FontAttributes="Bold" />
                    <Label Grid.Row="1"
                           Grid.Column="1"
                           Text="{Binding Location}"
                           FontAttributes="Italic"
                           VerticalOptions="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Элементы, указанные в DataTemplate определении внешнего вида каждого элемента в списке, и дочерний элемент DataTemplate должен быть Cell объектом. В примере макет в пределах объекта DataTemplate управляется Grid. Image Содержит Grid объект и два Label объекта, которые привязываются ко свойствам Monkey класса:

public class Monkey
{
    public string Name { get; set; }
    public string Location { get; set; }
    public string Details { get; set; }
    public string ImageUrl { get; set; }
}

На следующем снимке экрана показан результат создания шаблонов каждого элемента в списке:

Screenshot of ListView where each item is templated.

Дополнительные сведения о шаблонах данных см. в разделе "Шаблоны данных".

Cells

Внешний вид каждого элемента в объекте ListViewDataTemplateDataTemplate определяется и должен ссылаться на Cell класс для отображения элементов. Каждая ячейка представляет элемент данных в элементе ListView. .NET MAUI включает следующие встроенные ячейки:

  • TextCell, который отображает первичный и вторичный текст на отдельных строках.
  • ImageCell, который отображает изображение с первичным и вторичным текстом в отдельных строках.
  • SwitchCell, который отображает текст и переключатель, который можно включить или отключить.
  • EntryCell, который отображает метку и текст, который можно изменить.
  • ViewCell— настраиваемая ячейка, внешний вид которой определяется .View Этот тип ячейки следует использовать, если требуется полностью определить внешний вид каждого элемента в элементе ListView.

Как правило, SwitchCell и EntryCell будет использоваться только в объекте TableView и не будет использоваться в объекте ListView. Дополнительные сведения и SwitchCellEntryCellсведения см. в статье TableView.

Текстовая ячейка

На TextCell отдельных строках отображается основной и вторичный текст. TextCell определяет следующие свойства:

  • Text, тип string, определяет основной текст, который будет отображаться.
  • TextColorColorТип , представляет цвет первичного текста.
  • Detail, тип string, определяет вторичный текст, который будет отображаться.
  • DetailColorColorТип , указывает цвет вторичного текста.
  • CommandICommandТип , определяет команду, выполняемую при нажатии ячейки.
  • CommandParameterobjectТип , представляет параметр, переданный команде.

Эти свойства поддерживаются объектами BindableProperty, то есть эти свойства можно указывать в качестве целевых для привязки и стилизации данных.

В следующем примере показано, как TextCell определить внешний вид элементов в :ListView

<ListView ItemsSource="{Binding Food}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextCell Text="{Binding Name}"
                      Detail="{Binding Description}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

На следующем снимка экрана показана результирующая внешний вид ячейки:

Screenshot of ListView where each item is a TextCell.

Ячейка изображения

Отображает ImageCell изображение с первичным и вторичным текстом в отдельных строках. ImageCell наследует свойства от TextCellи определяет ImageSource свойство типа ImageSource, указывающее изображение, отображаемое в ячейке. Это свойство поддерживается BindableProperty объектом, что означает, что оно может быть целевым объектом привязок данных и стилем.

В следующем примере показано, как ImageCell определить внешний вид элементов в :ListView

<ListView ItemsSource="{Binding Food}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ImageCell ImageSource="{Binding Image}"
                       Text="{Binding Name}"
                       Detail="{Binding Description}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

На следующем снимка экрана показана результирующая внешний вид ячейки:

Screenshot of ListView where each item is an ImageCell.

Просмотр ячейки

A ViewCell — это настраиваемая ячейка, внешний вид которой определяется .View ViewCell определяет View свойство типа, Viewопределяющее представление, представляющее содержимое ячейки. Это свойство поддерживается BindableProperty объектом, что означает, что оно может быть целевым объектом привязок данных и стилем.

Примечание.

View — это свойство содержимого класса ViewCell. Поэтому его не нужно явно задавать из XAML.

В следующем примере показано, как ViewCell определить внешний вид элементов в :ListView

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid Padding="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Image Grid.RowSpan="2"
                           Source="{Binding ImageUrl}"
                           Aspect="AspectFill"
                           HeightRequest="60"
                           WidthRequest="60" />
                    <Label Grid.Column="1"
                           Text="{Binding Name}"
                           FontAttributes="Bold" />
                    <Label Grid.Row="1"
                           Grid.Column="1"
                           Text="{Binding Location}"
                           FontAttributes="Italic"
                           VerticalOptions="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

ViewCellВнутри макета можно управлять любым макетом .NET MAUI. В этом примере макет управляется с Gridпомощью . Image Содержит Grid объект и два Label объекта, которые привязываются ко свойствам Monkey класса.

На следующем снимке экрана показан результат создания шаблонов каждого элемента в списке:

Screenshot of ListView where each item is templated with a ViewCell.

Выбор внешнего вида элемента во время выполнения

Внешний вид каждого элемента в объекте ListView можно выбрать во время выполнения на основе значения элемента, задав свойству ItemTemplateDataTemplateSelector объект:

<ContentPage ...
             xmlns:templates="clr-namespace:ListViewDemos.Templates">
    <ContentPage.Resources>
        <DataTemplate x:Key="AmericanMonkeyTemplate">
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>

        <DataTemplate x:Key="OtherMonkeyTemplate">
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>

        <templates:MonkeyDataTemplateSelector x:Key="MonkeySelector"
                                             AmericanMonkey="{StaticResource AmericanMonkeyTemplate}"
                                             OtherMonkey="{StaticResource OtherMonkeyTemplate}" />
    </ContentPage.Resources>

    <StackLayout Margin="20">
        <ListView ItemsSource="{Binding Monkeys}"
                  ItemTemplate="{StaticResource MonkeySelector}" />
    </StackLayout>
</ContentPage>

Для ItemTemplate свойства задан MonkeyDataTemplateSelector объект. В следующем примере показан MonkeyDataTemplateSelector класс:

public class MonkeyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate AmericanMonkey { get; set; }
    public DataTemplate OtherMonkey { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        return ((Monkey)item).Location.Contains("America") ? AmericanMonkey : OtherMonkey;
    }
}

Класс MonkeyDataTemplateSelector определяет AmericanMonkey и OtherMonkeyDataTemplate свойства, которые задаются различными шаблонами данных. Переопределение OnSelectTemplate возвращает AmericanMonkey шаблон, который отображает имя обезьяны и расположение в подростке, когда имя обезьяны содержит "Америка". Если имя обезьяны не содержит "Америка", переопределение возвращает OtherMonkey шаблон, OnSelectTemplate который отображает имя обезьяны и расположение в серебре:

Screenshot of ListView runtime item template selection.

Дополнительные сведения о селекторах шаблонов данных см. в разделе "Создание объекта DataTemplateSelector".

Реагирование на выбор элемента

По умолчанию ListView выбор включен. Однако это поведение можно изменить, задав SelectionMode свойство. Перечисление ListViewSelectionMode определяет следующие члены:

  • None — указывает, что элементы не могут быть выбраны.
  • Single — указывает, что можно выбрать один элемент с выделенным элементом. Это значение по умолчанию.

ListViewItemSelected определяет событие, возникающее при SelectedItem изменении свойства, из-за выбора элемента из списка или при установке свойства приложением. Объект SelectedItemChangedEventArgs , сопровождающий это событие, имеет SelectedItem и SelectedItemIndex свойства.

SelectionMode Если для свойства задано Singleзначение, можно выбрать один элемент в элементеListView. При выборе SelectedItem элемента свойство будет задано значение выбранного элемента. При изменении ItemSelected этого свойства вызывается событие.

В следующем примере показано ListView , что может реагировать на выбор одного элемента:

<ListView ItemsSource="{Binding Monkeys}"
          ItemSelected="OnItemSelected">
    ...
</ListView>

В этом примере OnItemSelected обработчик событий выполняется при ItemSelected срабатывании события с помощью обработчика событий, извлекающего выбранный элемент:

void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
{
    Monkey item = args.SelectedItem as Monkey;
}

На следующем снимке экрана показан выбор одного элемента в :ListView

Screenshot of a ListView with a selection.

Очистка выделенного фрагмента

Свойство SelectedItem можно очистить, задав его или объект, к которым он привязывается.null

Отключение выделения

ListView Выбор включен по умолчанию. Однако его можно отключить, задав SelectionMode для свойства значение None:

<ListView ...
          SelectionMode="None" />

SelectionMode Если для свойства задано Noneзначение , элементы в ListView ней не могут быть выбраны, SelectedItem свойство останется nullи ItemSelected событие не будет запущено.

Кэширование данных

ListView — это мощное представление для отображения данных, но оно имеет некоторые ограничения. Производительность прокрутки может страдать при использовании пользовательских ячеек, особенно если они содержат иерархии глубоко вложенных представлений или используют определенные макеты, требующие сложного измерения. К счастью, есть методы, которые можно использовать, чтобы избежать плохой производительности.

Часто ListView используется для отображения гораздо большего объема данных, чем на экране. Например, у музыкального приложения может быть библиотека песен с тысячами записей. Создание элемента для каждой записи будет тратить ценную память и плохо работать. Постоянно создавая и уничтожая строки, приложение будет постоянно создавать экземпляры и очищать объекты, которые также будут работать плохо.

Для экономии памяти собственные ListView эквиваленты для каждой платформы имеют встроенные функции для повторного использования строк. Только ячейки, видимые на экране, загружаются в память, а содержимое загружается в существующие ячейки. Этот шаблон не позволяет приложению создавать экземпляры тысяч объектов, сохранять время и память.

.NET MAUI разрешает ListView повторное использование ячеек через ListViewCachingStrategy перечисление, которое определяет следующие элементы:

  • RetainElement, указывает, что ListView ячейка будет создаваться для каждого элемента в списке.
  • RecycleElementУказывает, что ListView попытка свести к минимуму объем памяти и скорость выполнения путем перезапуска ячеек списка.
  • RecycleElementAndDataTemplate, как RecycleElement и обеспечение того, что при ListView использовании DataTemplateSelectorDataTemplate объекта объекты кэшируются типом элемента в списке.

Сохранение элементов

Стратегия RetainElement кэширования указывает, что ListView будет создавать ячейку для каждого элемента в списке и является поведением по умолчанию ListView . Его следует использовать в следующих обстоятельствах:

  • Каждая ячейка имеет большое количество привязок (20–30+).
  • Шаблон ячейки часто изменяется.
  • Тестирование показывает, что RecycleElement стратегия кэширования приводит к снижению скорости выполнения.

Важно распознать последствия RetainElement стратегии кэширования при работе с пользовательскими ячейками. Любой код инициализации ячеек должен выполняться для каждого создания ячейки, что может быть несколько раз в секунду. В этом случае методы макета, которые были тонкими на странице, как использование нескольких вложенных StackLayout объектов, становятся узкими местами производительности при настройке и уничтожении в режиме реального времени при прокрутке пользователя.

Корзина элементов

Стратегия RecycleElement кэширования указывает, что ListView попытка свести к минимуму объем памяти и скорость выполнения путем перезапуска ячеек списка. Этот режим не всегда предлагает улучшение производительности и тестирование должно выполняться для определения каких-либо улучшений. Тем не менее, это предпочтительный выбор, и его следует использовать в следующих обстоятельствах:

  • Каждая ячейка имеет небольшое или умеренное количество привязок.
  • Каждая ячейка BindingContext определяет все данные ячейки.
  • Каждая ячейка в значительной степени аналогична шаблону ячейки.

Во время виртуализации ячейка будет обновлять контекст привязки и поэтому, если приложение использует этот режим, оно должно убедиться, что обновления контекста привязки обрабатываются соответствующим образом. Все данные о ячейке должны поступать из контекста привязки или ошибок согласованности. Эту проблему можно избежать с помощью привязки данных для отображения данных ячейки. Кроме того, данные ячеек должны быть заданы в переопределении, а не в OnBindingContextChanged конструкторе пользовательской ячейки, как показано в следующем примере:

public class CustomCell : ViewCell
{
    Image image = null;

    public CustomCell()
    {
        image = new Image();
        View = image;
    }

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();

        var item = BindingContext as ImageItem;
        if (item != null)
        {
            image.Source = item.ImageUrl;
        }
    }
}

Корзина элементов с помощью dataTemplateSelector

Если используется ListViewDataTemplateSelector для выбора DataTemplate, RecycleElement стратегия кэширования не кэширует DataTemplate объекты. Вместо этого выбирается для DataTemplate каждого элемента данных в списке.

Примечание.

Стратегия RecycleElement кэширования требует, чтобы при DataTemplateSelector запросе выбрать DataTemplate то, что каждый должен возвращать один DataTemplate и тот же ViewCell тип. Например, если задано ListView значение, DataTemplateSelector которое может возвращать MyDataTemplateA либо (где MyDataTemplateA возвращает типMyViewCellA), либо MyDataTemplateB (где MyDataTemplateB возвращает ViewCellMyViewCellBViewCell тип), когда MyDataTemplateA возвращается он должен возвращать MyViewCellA или возникает исключение.

Корзина элементов с dataTemplates

Стратегия RecycleElementAndDataTemplate кэширования основывается на RecycleElement стратегии кэширования, дополнительно гарантируя, что при ListView использовании DataTemplateSelector выбранного DataTemplateDataTemplate объекта объекты кэшируются типом элемента в списке. Таким образом, DataTemplate объекты выбираются один раз на тип элемента вместо одного экземпляра элемента.

Примечание.

Стратегия RecycleElementAndDataTemplate кэширования требует, чтобы DataTemplate объекты, возвращаемые DataTemplateSelector конструктором DataTemplate , который принимает Typeобъект.

Настройка стратегии кэширования

ListView Стратегия кэширования может быть определена в XAML, задав CachingStrategy атрибут:

<ListView CachingStrategy="RecycleElement">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
              ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

В C#стратегия кэширования устанавливается через перегрузку конструктора:

ListView listView = new ListView(ListViewCachingStrategy.RecycleElement);

Настройка стратегии кэширования в подклассном ListView

CachingStrategy Задание атрибута из XAML в подклассе ListView не приведет к возникновению требуемого поведения, так как в ней нет CachingStrategy свойстваListView. Решение этой проблемы заключается в указании конструктора подкласса ListView , который принимает ListViewCachingStrategy параметр и передает его базовому классу:

public class CustomListView : ListView
{
    public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
    {
    }
    ...
}

ListViewCachingStrategy Затем значение перечисления можно указать из XAML с помощью атрибутаx:Arguments:

<local:CustomListView>
    <x:Arguments>
        <ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
    </x:Arguments>
</local:CustomListView>

Колонтитулы

ListView может представлять верхний и нижний колонтитул, прокручиваемый элементами в списке. Верхний и нижний колонтитул могут быть строками, представлениями или DataTemplate объектами.

ListView определяет следующие свойства для указания верхнего и нижнего колонтитула:

  • HeaderobjectТип , указывает строку, привязку или представление, которое будет отображаться в начале списка.
  • HeaderTemplate, тип DataTemplate, указывает DataTemplate , что используется для форматирования Header.
  • FooterobjectТип , указывает строку, привязку или представление, которое будет отображаться в конце списка.
  • FooterTemplate, тип DataTemplate, указывает DataTemplate , что используется для форматирования Footer.

Эти свойства поддерживаются BindableProperty объектами, что означает, что свойства могут быть целевыми объектами привязки данных.

Значения Header и Footer свойства можно задать string , как показано в следующем примере:

<ListView ItemsSource="{Binding Monkeys}"
          Header="Monkeys"
          Footer="2022">
    ...
</ListView>

На следующем снимка экрана показан итоговый заголовок:

Screenshot of a ListView string header.

Для Header каждого Footer свойства можно задать представление. Это может быть одно представление или представление, содержащее несколько дочерних представлений. В следующем примере показаны Header свойства каждого Footer набора StackLayout для объекта, содержащего Label объект:

<ListView ItemsSource="{Binding Monkeys}">
    <ListView.Header>
        <StackLayout BackgroundColor="LightGray">
            <Label Margin="10,0,0,0"
                   Text="Monkeys"
                   FontSize="12"
                   FontAttributes="Bold" />
        </StackLayout>
    </ListView.Header>
    <ListView.Footer>
        <StackLayout BackgroundColor="LightGray">
            <Label Margin="10,0,0,0"
                   Text="Friends of Monkey"
                   FontSize="12"
                   FontAttributes="Bold" />
        </StackLayout>
    </ListView.Footer>
    ...
</ListView>

На следующем снимка экрана показан итоговый заголовок:

Screenshot of CollectionView header and footer using views.

FooterTemplate Свойства HeaderTemplate можно задать для DataTemplate объектов, которые используются для форматирования верхнего и нижнего колонтитулов. В этом сценарии HeaderFooter свойства должны привязаться к текущему источнику для применения шаблонов, как показано в следующем примере:

<ListView ItemsSource="{Binding Monkeys}"
          Header="{Binding .}"
          Footer="{Binding .}">
    <ListView.HeaderTemplate>
        <DataTemplate>
            <StackLayout BackgroundColor="LightGray">
                <Label Margin="10,0,0,0"
                       Text="Monkeys"
                       FontSize="12"
                       FontAttributes="Bold" />
            </StackLayout>
        </DataTemplate>
    </ListView.HeaderTemplate>
    <ListView.FooterTemplate>
        <DataTemplate>
            <StackLayout BackgroundColor="LightGray">
                <Label Margin="10,0,0,0"
                       Text="Friends of Monkey"
                       FontSize="12"
                       FontAttributes="Bold" />
            </StackLayout>
        </DataTemplate>
    </ListView.FooterTemplate>
    ...
</ListView>

Разделители элементов управления

По умолчанию разделители отображаются между ListView элементами в iOS и Android. Это поведение можно изменить, задав SeparatorVisibility для свойства тип SeparatorVisibility, значение None:

<ListView ...
          SeparatorVisibility="None" />

Кроме того, если разделитель включен, его цвет можно задать со свойством SeparatorColor :

<ListView ...
          SeparatorColor="Blue" />

Элементы размера

По умолчанию все элементы в ListView одном и том же высоте, что является производным от содержимого элемента, определяющего DataTemplate внешний вид каждого элемента. Однако это поведение можно изменить с помощью HasUnevenRows свойств и RowHeight свойств. По умолчанию HasUnevenRows свойство равно false.

Для RowHeight свойства можно задать int значение, представляющее высоту каждого элемента в заданном ListViewобъекте HasUnevenRowsfalse. Если HasUnevenRows задано значение true, каждый элемент в элементе ListView может иметь другую высоту. Высота каждого элемента будет производным от содержимого элемента DataTemplate, поэтому каждый элемент будет иметь размер в его содержимом.

Отдельные ListView элементы могут быть программно изменены во время выполнения путем изменения свойств, связанных с макетом элементов внутри DataTemplateэлемента, при условии, что HasUnevenRows это свойство true. В следующем примере изменяется высота Image объекта при нажатии:

void OnImageTapped(object sender, EventArgs args)
{
    Image image = sender as Image;
    ViewCell viewCell = image.Parent.Parent as ViewCell;

    if (image.HeightRequest < 250)
    {
      image.HeightRequest = image.Height + 100;
      viewCell.ForceUpdateSize();
    }
}

В этом примере OnImageTapped обработчик событий выполняется в ответ на Image касания объекта. Обработчик событий обновляет высоту ImageCell.ForceUpdateSize и метод обновляет размер ячейки, даже если она в настоящее время не отображается.

Предупреждение

Чрезмерное использование динамического размера элементов может привести ListView к снижению производительности.

Макет справа налево

ListView может макетировать содержимое в направлении потока справа налево, задав для свойства значение FlowDirectionRightToLeft. FlowDirection Однако свойство в идеале должно быть задано на странице или корневом макете, что приводит ко всем элементам страницы или корневому макету для реагирования на направление потока:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ListViewDemos.RightToLeftListPage"
             Title="Right to left list"
             FlowDirection="RightToLeft">
    <StackLayout Margin="20">
        <ListView ItemsSource="{Binding Monkeys}">
            ...
        </ListView>
    </StackLayout>
</ContentPage>

Значение по умолчанию FlowDirection для элемента с родительским MatchParentэлементом . Поэтому значение ListView свойства наследуется FlowDirection от StackLayoutзначения, которое, в свою очередь, наследует FlowDirection значение свойства от ContentPage.

Отображение сгруппированных данных

Большие наборы данных часто становятся неуправляемыми при постоянной прокрутке списка. В этом сценарии упорядочение данных в группы может улучшить взаимодействие с пользователем, упрощая навигацию по данным.

Перед отображением данных необходимо сгруппировать. Это можно сделать, создав список групп, где каждая группа является списком элементов. Список групп должен быть коллекцией IEnumerable<T> , где T определяется два фрагмента данных:

  • Имя группы.
  • Коллекция IEnumerable , определяющая элементы, принадлежащие группе.

Таким образом, процесс группировки данных заключается в том, чтобы:

  • Создайте тип, который моделирует один элемент.
  • Создайте тип, который моделирует одну группу элементов.
  • Создайте коллекцию IEnumerable<T> , где T используется тип, который моделирует одну группу элементов. Эта коллекция представляет собой коллекцию групп, в которой хранятся сгруппированные данные.
  • Добавьте данные в коллекцию IEnumerable<T> .

Пример

При группировке данных первым шагом является создание типа, моделирующего один элемент. В следующем примере показан Animal класс:

public class Animal
{
    public string Name { get; set; }
    public string Location { get; set; }
    public string Details { get; set; }
    public string ImageUrl { get; set; }
}

Класс Animal моделирует один элемент. Затем можно создать тип, который моделирует группу элементов. В следующем примере показан AnimalGroup класс:

public class AnimalGroup : List<Animal>
{
    public string Name { get; private set; }

    public AnimalGroup(string name, List<Animal> animals) : base(animals)
    {
        Name = name;
    }
}

Класс AnimalGroup наследует от List<T> класса и добавляет Name свойство, представляющее имя группы.

Затем можно создать коллекцию IEnumerable<T> групп:

public List<AnimalGroup> Animals { get; private set; } = new List<AnimalGroup>();

Этот код определяет коллекцию с именем Animals, где каждый элемент в коллекции является AnimalGroup объектом. Каждый AnimalGroup объект состоит из имени и List<Animal> коллекции, которая определяет Animal объекты в группе.

Затем группированные данные можно добавить в коллекцию Animals :

Animals.Add(new AnimalGroup("Bears", new List<Animal>
{
    new Animal
    {
        Name = "American Black Bear",
        Location = "North America",
        Details = "Details about the bear go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/0/08/01_Schwarzbär.jpg"
    },
    new Animal
    {
        Name = "Asian Black Bear",
        Location = "Asia",
        Details = "Details about the bear go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG/180px-Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG"
    },
    // ...
}));

Animals.Add(new AnimalGroup("Monkeys", new List<Animal>
{
    new Animal
    {
        Name = "Baboon",
        Location = "Africa & Asia",
        Details = "Details about the monkey go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg"
    },
    new Animal
    {
        Name = "Capuchin Monkey",
        Location = "Central & South America",
        Details = "Details about the monkey go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg"
    },
    new Animal
    {
        Name = "Blue Monkey",
        Location = "Central and East Africa",
        Details = "Details about the monkey go here.",
        ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg"
    },
    // ...
}));

Этот код создает две группы в Animals коллекции. Первый AnimalGroup называется Bearsи содержит коллекцию List<Animal> сведений о медведе. Второй AnimalGroup называется Monkeysи содержит коллекцию List<Animal> подробностей обезьяны.

ListView отображает сгруппированные данные, если данные были правильно сгруппированы, задав IsGroupingEnabled для свойства trueзначение :

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="True">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid Padding="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Image Grid.RowSpan="2"
                           Source="{Binding ImageUrl}"
                           Aspect="AspectFill"
                           HeightRequest="60"
                           WidthRequest="60" />
                    <Label Grid.Column="1"
                           Text="{Binding Name}"
                           FontAttributes="Bold" />
                    <Label Grid.Row="1"
                           Grid.Column="1"
                           Text="{Binding Location}"
                           FontAttributes="Italic"
                           VerticalOptions="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Эквивалентный код на C# выглядит так:

ListView listView = new ListView
{
    IsGroupingEnabled = true
};
listView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");
// ...

Внешний вид каждого элемента в объекте ListView определяется путем задания его ItemTemplate свойства в значение DataTemplate. Дополнительные сведения см. в разделе "Определение внешнего вида элемента".

На следующем снимка экрана показан ListView сгруппированные данные:

Screenshot of grouped data in a ListView.

Примечание.

По умолчанию ListView отобразится имя группы в заголовке группы. Это поведение можно изменить, настроив заголовок группы.

Настройка заголовка группы

Внешний вид каждого заголовка группы можно настроить, задав ListView.GroupHeaderTemplate для свойства значение DataTemplate:

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="True">
    <ListView.GroupHeaderTemplate>
        <DataTemplate>
            <ViewCell>
                <Label Text="{Binding Name}"
                       BackgroundColor="LightGray"
                       FontSize="18"
                       FontAttributes="Bold" />
            </ViewCell>
        </DataTemplate>
    </ListView.GroupHeaderTemplate>
    ...
</ListView>

В этом примере для каждого заголовка группы задано Label значение, отображающее имя группы и которое имеет другие свойства внешнего вида. На следующем снимка экрана показан заголовок настраиваемой группы:

Screenshot of a customized group header in a ListView.

Важно!

Свойство GroupHeaderTemplate является взаимоисключающим с свойством GroupDisplayBinding . Поэтому оба свойства не должны быть заданы.

Группа без шаблонов

ListViewможет отображать правильно сгруппированные данные, не устанавливая для DataTemplateсвойства значение ItemTemplate :

<ListView ItemsSource="{Binding Animals}"
          IsGroupingEnabled="true" />

В этом сценарии значимые данные можно отобразить, переопределив метод в типе, который моделирует ToString один элемент, и тип, который моделирует одну группу элементов.

Управление прокруткой

ListView определяет два ScrollTo метода, которые прокручивают элементы в представление. Одна из перегрузок прокручивает указанный элемент в представление, а другая прокручивает указанный элемент в указанной группе в представление. Обе перегрузки имеют дополнительные аргументы, позволяющие точное положение элемента после завершения прокрутки, а также необходимость анимации прокрутки.

ListViewScrollToRequested определяет событие, которое запускается при вызове ScrollTo одного из методов. ОбъектScrollToRequestedEventArgs, сопровождающий ScrollToRequested событие, имеет множество свойств, включая ShouldAnimate, ElementModeи Position. Некоторые из этих свойств задаются из аргументов, указанных в ScrollTo вызовах метода.

Кроме того, ListView определяет Scrolled событие, которое запускается, чтобы указать, что произошла прокрутка. Объект ScrolledEventArgs , сопровождающий Scrolled событие, имеет ScrollX и ScrollY свойства.

Обнаружение прокрутки

ListViewScrolled определяет событие, которое запускается, чтобы указать, что произошла прокрутка. Класс ItemsViewScrolledEventArgs , представляющий объект, который сопровождает Scrolled событие, определяет следующие свойства:

  • ScrollX, тип double, представляет положение X прокрутки
  • ScrollYdoubleтип , представляет положение Y прокрутки.

В следующем примере XAML показан ListView обработчик событий для Scrolled события:

<ListView Scrolled="OnListViewScrolled">
    ...
</ListView>

Эквивалентный код на C# выглядит так:

ListView listView = new ListView();
listView.Scrolled += OnListViewScrolled;

В этом примере OnListViewScrolled кода обработчик событий выполняется при Scrolled срабатывании события:

void OnListViewScrolled(object sender, ScrolledEventArgs e)
{
    // Custom logic
}

Важно!

Событие Scrolled запускается для прокручиваемых пользователем прокрутк и для программных прокрутк.

Прокрутка элемента в представление

Метод ScrollTo прокручивает указанный элемент в представление. Учитывая ListView объект с именем listView, в следующем примере показано, как прокрутить элемент Обезьяны Proboscis в представление:

MonkeysViewModel viewModel = BindingContext as MonkeysViewModel;
Monkey monkey = viewModel.Monkeys.FirstOrDefault(m => m.Name == "Proboscis Monkey");
listView.ScrollTo(monkey, ScrollToPosition.MakeVisible, true);

Кроме того, элемент в сгруппированных данных можно прокрутить в представление, указав элемент и группу. В следующем примере показано, как прокрутить элемент Обезьяны Proboscis в группе "Обезьяны" в представление:

GroupedAnimalsViewModel viewModel = BindingContext as GroupedAnimalsViewModel;
AnimalGroup group = viewModel.Animals.FirstOrDefault(a => a.Name == "Monkeys");
Animal monkey = group.FirstOrDefault(m => m.Name == "Proboscis Monkey");
listView.ScrollTo(monkey, group, ScrollToPosition.MakeVisible, true);

Примечание.

Событие ScrollToRequested запускается при вызове ScrollTo метода.

Отключение анимации прокрутки

Анимация прокрутки отображается при прокрутке элемента в представление. Однако эту анимацию можно отключить, задав animated аргумент ScrollTo метода falseследующим образом:

listView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible, animate: false);

Положение прокрутки элемента управления

При прокрутке элемента в представление точное положение элемента после завершения прокрутки можно указать с position аргументом ScrollTo методов. Этот аргумент принимает ScrollToPosition член перечисления.

MakeVisible

Элемент ScrollToPosition.MakeVisible указывает, что элемент должен быть прокручен до тех пор, пока он не отображается в представлении:

listView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible, animate: true);

Начать с

Элемент ScrollToPosition.Start указывает, что элемент должен прокручиваться до начала представления:

listView.ScrollTo(monkey, position: ScrollToPosition.Start, animate: true);

Центр

Элемент ScrollToPosition.Center указывает, что элемент должен быть прокручен в центр представления:

listView.ScrollTo(monkey, position: ScrollToPosition.Center, animate: true);

Завершить

Элемент ScrollToPosition.End указывает, что элемент должен быть прокручен до конца представления:

listView.ScrollTo(monkey, position: ScrollToPosition.End, animate: true);

Видимость полосы прокрутки

ListViewHorizontalScrollBarVisibility определяет и VerticalScrollBarVisibility свойства, которые поддерживаются привязываемыми свойствами. Эти свойства получают или задают ScrollBarVisibility значение перечисления, представляющее, когда отображается горизонтальная или вертикальная полоса прокрутки. Перечисление ScrollBarVisibility определяет следующие члены:

  • Default указывает поведение полосы прокрутки по умолчанию для платформы и является значением по умолчанию для HorizontalScrollBarVisibility свойств и VerticalScrollBarVisibility свойств.
  • Always указывает, что полосы прокрутки будут видимыми, даже если содержимое помещается в представление.
  • Never указывает, что полосы прокрутки не будут видимыми, даже если содержимое не помещается в представление.

Добавление контекстных меню

ListView поддерживает элементы контекстного меню, которые определяются как MenuItem объекты, добавляемые в коллекцию ViewCell.ContextActions в каждом элементе DataTemplate :

<ListView x:Name="listView"
          ItemsSource="{Binding Monkeys}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <ViewCell.ContextActions>
                    <MenuItem Text="Favorite"
                              Command="{Binding Source={x:Reference listView}, Path=BindingContext.FavoriteCommand}"
                              CommandParameter="{Binding}" />
                    <MenuItem Text="Delete"
                              Command="{Binding Source={x:Reference listView}, Path=BindingContext.DeleteCommand}"
                              CommandParameter="{Binding}" />
                </ViewCell.ContextActions>

                ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Объекты MenuItem отображаются при щелчке элемента правой ListView кнопкой мыши:

Screenshot of CollectionView context menu items.

Дополнительные сведения о элементах меню см. в разделе "Отображение элементов меню".

Потяните, чтобы обновить

ListView поддерживает вытягивание для обновления функциональных возможностей, что позволяет обновлять данные, отображаемые путем извлечения списка элементов.

Чтобы включить обновление по запросу IsPullToRefreshEnabled , задайте для свойства значение true. При активации ListView обновления вызывает Refreshing событие, а IsRefreshing свойство будет задано true. Код, необходимый для обновления содержимого ListView , затем должен выполняться обработчиком события Refreshing или ICommand реализацией RefreshCommand выполнения. ListView После обновления IsRefreshing свойство должно быть задано falseили EndRefresh метод должен вызываться для объектаListView, чтобы указать, что обновление завершено.

В следующем примере показано ListView , как использовать вытягивание для обновления:

<ListView ItemsSource="{Binding Animals}"
          IsPullToRefreshEnabled="true"
          RefreshCommand="{Binding RefreshCommand}"
          IsRefreshing="{Binding IsRefreshing}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                ...
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

В этом примере, когда пользователь инициирует обновление, выполняется свойство, ICommandRefreshCommand которое должно обновить отображаемые элементы. Визуализация обновления отображается во время обновления, которая состоит из анимированного круга хода выполнения. Значение IsRefreshing свойства указывает текущее состояние операции обновления. При активации обновления это свойство автоматически перейдет в true. После завершения обновления необходимо сбросить свойство falseв значение .