Skip to content

Начало работы с контролом ListView

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

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

listview-getstarted-result

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

Создание нового приложения

Создайте новое Eremex Avalonia .NET MVVM-приложение . Назовите его ListView-example.

listview-getstarted-newapp-wizard

Чтобы отобразить картинки в формате SVG, добавьте пакет NuGet Avalonia.Svg.Skia в проект.

Определите источник объекта

В файле MainWindowViewModel.cs создайте класс ItemViewModel, который инкапсулирует объект элемента.

public partial class ItemViewModel : ObservableObject
{
    [ObservableProperty] private int invoiceId;
    [ObservableProperty] private string shipCountry;
    [ObservableProperty] private DateTime date;
    [ObservableProperty] private IImage flag;

    public ItemViewModel(int id, string shipCountry, IImage flag)
    {
        InvoiceId = id;
        ShipCountry = shipCountry;
        Random random = new Random();
        Date = new DateTime(DateTime.Now.Year, random.Next(1, 12), random.Next(1, 28));
        Flag = flag;
    }
}

Свойства InvoiceId, Date и Flag, предоставляемые классом ItemViewModel, содержат значения для отображения в элементах ListView. Свойство ItemViewModel.ShipCountry указывает страну доставки, связанную с элементом. Элементы ListView будут сгруппированы по этому свойству.

Создайте и инициализируйте коллекцию Items в классе MainWindowViewModel, как показано ниже. Следующий код заполняет коллекцию Items тремя наборами элементов. Каждый набор элементов связан со своей собственной страной доставки (China, Brazil и India).

using CommunityToolkit.Mvvm.ComponentModel;
using Avalonia.Svg.Skia;
using Eremex.AvaloniaUI.Controls.Utils;

public partial class MainWindowViewModel : ViewModelBase
{
    [ObservableProperty] 
    private List<ItemViewModel> items;

    public MainWindowViewModel()
    {
        SvgImage chinaFlag = ImageLoader.LoadSvgImage(Assembly.GetExecutingAssembly(), "Assets/china-flag.svg");
        SvgImage indiaFlag = ImageLoader.LoadSvgImage(Assembly.GetExecutingAssembly(), "Assets/india-flag.svg");
        SvgImage brazilFlag = ImageLoader.LoadSvgImage(Assembly.GetExecutingAssembly(), "Assets/brazil-flag.svg");

        Random random = new Random();
        Items = new List<ItemViewModel>();
        for (int i = 1; i < 10; i++)
        {
            Items.Add(new ItemViewModel(random.Next(500), "China", chinaFlag));
        }

        for (int i = 1; i < 5; i++)
        {
            Items.Add(new ItemViewModel(random.Next(500), "Brazil", brazilFlag));
        }

        for (int i = 1; i < 8; i++)
        {
            Items.Add(new ItemViewModel(random.Next(500), "India", indiaFlag));
        }
    }
}

Метод Eremex.AvaloniaUI.Controls.Utils.ImageLoader.LoadSvgImage используется для загрузки SVG-картинок, хранящихся в определенной папке текущего проекта. Предполагается, что картинки SVG помещены в папку Assets, и их свойству Build Action присвоено значение AvaloniaResource. Убедитесь, что пакет Avalonia.Svg.Skia включен в проект.

Создание контрола ListView

Откройте файл MainWindow.axaml и определите компонент ListViewControl в XAML.

xmlns:mxlv="https://schemas.eremexcontrols.net/avalonia/listview"

<mxlv:ListViewControl Name="listViewControl1">
</mxlv:ListViewControl>

Привязать ListView к коллекции элементов

Убедитесь, что для DataContext главного окна и, следовательно, для DataContext ListView задан объект MainWindowViewModel. Смотрите файл App.axaml.cs, который присваивает DataContext главному окну.

Привяжите ListView к коллекции элементов, определенных в классе MainWindowViewModel, используя свойство ListViewControl.ItemsSource.

<mxlv:ListViewControl Name="listViewControl1" ItemsSource="{Binding Items}">
</mxlv:ListViewControl>

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

Для элементов в контроле ListView отсутствует дефолтная отрисовка. Чтобы отобразить элементы определенным образом, укажите шаблон элемента из свойства ListViewControl.ItemTemplate.

В приведенном ниже коде шаблон элемента определяет ограниченный объект сетки с двумя текстовыми блоками и картинкой внутри. Текстовые блоки отображают значения свойств ItemViewModel.InvoiceId и ItemViewModel.Date соответственно. Контрол картинки привязан к свойству __ItemViewModel.Flag_, в котором хранится картинка в формате SVG.

listview-getstarted-itemtemplate

<mxlv:ListViewControl Name="listViewControl1" ItemsSource="{Binding Items}">
    <mxlv:ListViewControl.ItemTemplate>
        <DataTemplate DataType="vm:ItemViewModel">
            <Border BorderBrush="DarkGray" BorderThickness="1">
                <Grid RowDefinitions="2*, *" Margin="3">
                    <TextBlock Text="{Binding InvoiceId, StringFormat={}Invoice: {0}}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                    <DockPanel Grid.Row="1" VerticalAlignment="Center">
                        <TextBlock Text="{Binding Date, StringFormat=yyyy-MM-dd}" FontSize="8" DockPanel.Dock="Left"/>
                        <Image Width="20"  DockPanel.Dock="Right" Source="{Binding Flag}"/>
                    </DockPanel>
                </Grid>
            </Border>
        </DataTemplate>
    </mxlv:ListViewControl.ItemTemplate>
</mxlv:ListViewControl>

Укажите размер элемента

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

Если размер элемента по умолчанию не соответствует вашим потребностям, вы можете использовать свойства ListViewControl.ItemWidth и ListViewControl.ItemHeight, чтобы указать пользовательский размер элемента. Приведенный ниже код применяет пользовательский размер элемента к элементам ListView.

<mxlv:ListViewControl Name="listViewControl1" ItemsSource="{Binding Items}" 
    ItemHeight="70" ItemWidth="100">

Групповые элементы

Вы можете сортировать и/или группировать элементы ListView по неограниченному количеству свойств элемента. Когда вы группируете по свойству, создаются групповые строки, объединяющие элементы. Обратите внимание, что групповые строки автоматически сортируются по свойству group.

listview-getstarted-grouprows

Коллекция ListViewControl.SortInfo определяет свойства элемента, используемые для сортировки и группировки элементов. Чтобы сгруппировать элементы, выполните следующие действия:

  • Добавьте объект(ы) ListViewSortInfo в коллекцию ListViewControl.SortInfo. Установите для элемента ListViewSortInfo.FieldName значение свойства элемента, по которому следует группировать элементы. При необходимости используйте свойство ListViewSortInfo.SortDirection, чтобы выбрать между порядком сортировки по возрастанию и по убыванию, в котором будут размещены группирующие строки.
  • Задайте свойству ListViewControl.GroupCount значение number of group levels (групповые свойства). ListViewControl.GroupCount указывает, сколько объектов ListViewSortInfo, начиная с начала коллекции ListViewControl.SortInfo, используется для группировки данных. Если вы группируете по одному свойству, установите для GroupCount значение 1. Если вы группируете по двум свойствам, установите для GroupCount значение 2 и так далее.

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

<mxlv:ListViewControl Name="listViewControl1" ItemsSource="{Binding Items}" 
        ItemHeight="40" ItemWidth="60"
        GroupCount="1">
    <mxlv:ListViewControl.SortInfo>
        <mxlv:ListViewSortInfo FieldName="ShipCountry" SortDirection="Ascending" />
    </mxlv:ListViewControl.SortInfo>
    <!-- ... -->
</mxlv:ListViewControl>

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

Давайте отсортируем элементы в каждой группе по свойству элемента Date в порядке убывания. Для этой цели добавьте новый объект ListViewSortInfo в коллекцию ListViewControl.SortInfo и установите для его элементов ListViewSortInfo.FieldName и ListViewSortInfo.SortDirection соответствующие значения.

<mxlv:ListViewControl.SortInfo>
    <mxlv:ListViewSortInfo FieldName="ShipCountry" SortDirection="Ascending" />
    <mxlv:ListViewSortInfo FieldName="Date" SortDirection="Descending" />
</mxlv:ListViewControl.SortInfo>

Поскольку свойству ListViewControl.GroupCount присвоено значение 1, первый объект ListViewSortInfo в коллекции ListViewControl.SortInfo указывает поле, используемое для группировки данных. Второй объект ListViewSortInfo относится к полю, используемому только для сортировки данных.

Выберите режим расположения элементов

ListView поддерживает два режима расположения элементов, которые вы можете выбрать с помощью свойства ListViewControl.ItemLayoutMode:

  • ListViewItemLayoutMode.Wrap (по умолчанию) — элементы размещены поперек, а затем вниз. Они автоматически обтекаются по правому краю контрола, создавая несколько линий.

    listview-getstarted-itemlayoutmode-wrap

  • ListViewItemLayoutMode.Stack — Элементы размещены в вертикальном списке. Они растягиваются, подгоняя их под ширину LayoutView.

    listview-getstarted-itemlayoutmode-stack

В этом руководстве мы будем придерживаться режима размещения Wrap по умолчанию.

Получить сфокусированный (выбранный) Элемент

Когда пользователь щелкает по определенному элементу с помощью мыши или клавиатуры в режиме выбора одного элемента, фокусируемый элемент изменяется. Вы можете использовать свойство ListViewControl.FocusedItem или ListViewControl.FocusedItemIndex для идентификации сфокусированного элемента.

Следующий код определяет свойство FocusedItem в модели основного представления и привязывает элемент ListViewControl.FocusedItem к этому свойству.

//MainWindowViewModel.cs
public partial class MainWindowViewModel : ViewModelBase
{
    //...
    ItemViewModel focusedItem;
    ItemViewModel FocusedItem {
        get {
            return focusedItem;
        }
        set
        {
            if (value != focusedItem)
            {
                focusedItem = value;
                // Perform actions when the focused item changes.
            }
        }
    }
}
<!-- MainWindow.axaml -->
<mxlv:ListViewControl Name="listViewControl1" ItemsSource="{Binding Items}"
                      ItemHeight="70" ItemWidth="100"
                      GroupCount="1"
                      FocusedItem="{Binding FocusedItem, Mode=TwoWay}"
                      >

Чтобы разрешить одновременный выбор нескольких элементов, установите для свойства ListViewControl.SelectionMode значение Multiple. В этом случае вы можете извлечь выбранные элементы из коллекции ListViewControl.SelectedItems.

Результат

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

listview-getstarted-result

Полный код

MainWindow.axaml:

<mx:MxWindow xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:ListView_example.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:mx="https://schemas.eremexcontrols.net/avalonia"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="ListView_example.Views.MainWindow"
        x:DataType="vm:MainWindowViewModel"
        Icon="/Assets/EMXControls.ico"
        Title="ListView_example"
        xmlns:mxlv="https://schemas.eremexcontrols.net/avalonia/listview"
        >

    <Design.DataContext>
        <!-- This only sets the DataContext for the previewer in an IDE,
             to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
        <vm:MainWindowViewModel/>
    </Design.DataContext>
    <Border BorderBrush="LightGray" BorderThickness="1" Margin="5">
        <mxlv:ListViewControl Name="listViewControl1" ItemsSource="{Binding Items}"
                              ItemHeight="70" ItemWidth="100"
                              GroupCount="1"
                              FocusedItem="{Binding FocusedItem, Mode=TwoWay}" SelectionMode="Multiple" SelectedItems=""
                              >
            <mxlv:ListViewControl.SortInfo>
                <mxlv:ListViewSortInfo FieldName="ShipCountry" SortDirection="Ascending" />
                <mxlv:ListViewSortInfo FieldName="Date" SortDirection="Descending" />
            </mxlv:ListViewControl.SortInfo>

            <mxlv:ListViewControl.ItemTemplate>
                <DataTemplate DataType="vm:ItemViewModel">
                    <Border BorderBrush="DarkGray" BorderThickness="1">
                        <Grid RowDefinitions="2*, *" Margin="3">
                            <TextBlock Text="{Binding InvoiceId, StringFormat={}Invoice: {0}}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                            <DockPanel Grid.Row="1" VerticalAlignment="Center">
                                <TextBlock Text="{Binding Date, StringFormat=yyyy-MM-dd}" FontSize="8" DockPanel.Dock="Left"/>
                                <Image Width="20"  DockPanel.Dock="Right" Source="{Binding Flag}"/>
                            </DockPanel>
                        </Grid>
                    </Border>
                </DataTemplate>
            </mxlv:ListViewControl.ItemTemplate>
        </mxlv:ListViewControl>
    </Border>
</mx:MxWindow>

MainWindowViewModel.cs:

using Avalonia.Media;
using Avalonia.Svg.Skia;
using CommunityToolkit.Mvvm.ComponentModel;
using Eremex.AvaloniaUI.Controls.ListView;
using Eremex.AvaloniaUI.Controls.Utils;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml.Linq;

namespace ListView_example.ViewModels;

public partial class MainWindowViewModel : ViewModelBase
{
    [ObservableProperty] 
    private List<ItemViewModel> items;

    public MainWindowViewModel()
    {
        SvgImage chinaFlag = ImageLoader.LoadSvgImage(Assembly.GetExecutingAssembly(), "Assets/china-flag.svg");
        SvgImage indiaFlag = ImageLoader.LoadSvgImage(Assembly.GetExecutingAssembly(), "Assets/india-flag.svg");
        SvgImage brazilFlag = ImageLoader.LoadSvgImage(Assembly.GetExecutingAssembly(), "Assets/brazil-flag.svg");

        Random random = new Random();
        Items = new List<ItemViewModel>();
        for (int i = 1; i < 10; i++)
        {
            Items.Add(new ItemViewModel(random.Next(500), "China", chinaFlag));
        }

        for (int i = 1; i < 5; i++)
        {
            Items.Add(new ItemViewModel(random.Next(500), "Brazil", brazilFlag));
        }

        for (int i = 1; i < 8; i++)
        {
            Items.Add(new ItemViewModel(random.Next(500), "India", indiaFlag));
        }

        // Set focus to the first item in the item collection.
        focusedItem = Items[0];
    }

    ItemViewModel focusedItem;
    ItemViewModel FocusedItem {
        get {
            return focusedItem;
        }
        set
        {
            if (value != focusedItem)
            {
                focusedItem = value;
                // Perform actions when the focused item changes.
            }
        }
    }
}

public partial class ItemViewModel : ObservableObject
{
    [ObservableProperty] private int invoiceId;
    [ObservableProperty] private string shipCountry;
    [ObservableProperty] private DateTime date;
    [ObservableProperty] private IImage flag;

    public ItemViewModel(int id, string shipCountry, IImage flag)
    {
        InvoiceId = id;
        ShipCountry = shipCountry;
        Random random = new Random();
        Date = new DateTime(DateTime.Now.Year, random.Next(1, 12), random.Next(1, 28));
        Flag = flag;
    }
}

Картинки *.svg, используемые в этом руководстве, помещены в папку Assets проекта. У них для свойства Build Action установлено значение AvaloniaResource.



* Эта страница была создана автоматически с помощью сервиса машинного перевода Яндекс Переводчик.