Привязка данных и списки

Завершено

Tech logo of U W P and W P F. W P F appears dimmed.

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

1. Создание ColorDescriptor класса

Создадим класс для представления цвета. В обозревателе решений щелкните проект DatabindingSample правой кнопкой мыши, выберите Добавить/Класс и введите ColorDescriptor в качестве имени класса. Щелкните Добавить, чтобы создать класс.

ColorDescriptor содержит два свойства: сам цвет как объект Windows.UI.Color и имя цвета. Он также содержит конструктор, который заполняет эти свойства, метод ToString(), который отображает название цвета, и шестнадцатеричные значения для компонентов цветов R, G и B. Так выглядит весь класс ColorDescriptor.

using Windows.UI;

namespace DatabindingSample
{
    public class ColorDescriptor : ObservableObject
    {
        public ColorDescriptor(Color color, string name)
        {
            Color = color;
            Name = name;
        }

        public Color Color { get; private set; }

        public string Name { get; private set; }

        public override string ToString()
        {
            return $"{Name} (#{Color.R:X2}{Color.G:X2}{Color.B:X2})";
        }
    }
}

Замените содержимое файла ColorDescriptor.cs по умолчанию приведенным выше кодом.

2. Создание страницы ColorList.xaml

Для отображения списка цветов мы будем использовать новую страницу XAML. В обозревателе решений щелкните правой кнопкой мыши проект DatabindingSample и выберите Добавить/Новый элемент. Выберите Пустая страница из списка доступных элементов и введите ColorList в качестве имени. Щелкните Добавить, чтобы создать страницу.

Screenshot that shows Blank Page selected under Visual C Sharp, in the Add New Item dialog box.

3. Настройка начальной страницы

Теперь, если вы запустите приложение, оно откроется на странице MainPage. Так как вы собираетесь работать с новой страницей ColorList.xaml, было бы неплохо сделать ее начальной. Для этого откройте файл App.xaml.cs и найдите строку, которая совершает переход к MainPage.

rootFrame.Navigate(typeof(MainPage), e.Arguments);

Замените MainPage на ColorList и убедитесь, что страница ColorList запускается при запуске приложения (нажмите F5 или выберите Отладка/Начать отладку).

4. Создание логики для списка цветов

Мы продолжим следовать ранее представленной рекомендации по созданию отдельной логики для новой страницы. Создадим новый класс с именем ColorListLogic.

В обозревателе решений щелкните проект DatabindingSample правой кнопкой мыши, выберите Добавить/Класс и введите ColorListLogic в качестве имени класса. Щелкните Добавить, чтобы создать класс, и вставьте в файл следующее:

using System.Collections.Generic;
using System.Collections.ObjectModel;

using Windows.UI;

namespace DatabindingSample
{
    public class ColorListLogic : ObservableObject
    {
        public List<ColorDescriptor> LotsOfColors { get; private set; }

        public ColorListLogic()
        {
            LotsOfColors = new List<ColorDescriptor>
            {
               new ColorDescriptor(Colors.Red, "red"),
               new ColorDescriptor(Colors.White, "white"),
               new ColorDescriptor(Colors.Green, "green"),
               new ColorDescriptor(Colors.Yellow, "yellow"),
               new ColorDescriptor(Colors.Blue, "blue"),
               new ColorDescriptor(Colors.Black, "black")
            };

        }
    }
}

Класс ColorListLogic пока очень прост. Он содержит свойство LotsOfColors, которое является элементом List объектов ColorDescriptor. Список заполняется некоторыми цветами в конструкторе класса. И это все.

5. Отображение цветов в ListBox

Следующий шаг — отображение цветов в нашем приложении. Сначала сделаем ColorListLogic доступным из XAML. Откройте ColorList.xaml.cs и добавьте его в класс ColorList:

public ColorListLogic Logic { get; } = new ColorListLogic();

Мы используем тот же синтаксис, что и для MainPageLogic перед этим. Он создает свойство, доступное только для возвращения, и инициализирует его значение для нового объекта ColorListLogic.

Затем откройте файл ColorList.xaml и добавьте следующий код XAML внутри элемента Grid.

<ListBox ItemsSource="{x:Bind Logic.LotsOfColors}" 
         Margin="20" 
         Width="200"
         HorizontalAlignment="Left" 
         VerticalAlignment="Top"/>

Здесь интересен атрибут ItemsSource. Он предоставляет источник элементов, отображаемых в ListBox. Он также просто привязан к свойству LotsOfColors элемента ColorListLogic.

Если вы запустите приложение сейчас, оно отобразит цвета в ListBox. Выглядит не очень хорошо. Похоже, что ListBox вызвал метод ToString() элемента ColorDescriptor, хранящегося в списке LotsOfColors.

Screenshot that shows the Data binding Sample window, with yellow selected.

6. Определение шаблона для элементов

Было бы приятно иметь шаблон, показывающий фактический цвет, хранящийся в свойстве ColorDescriptor.Color , и его имя. Примерно следующим образом:

Screenshot of template.

Чтобы добавить нужный код в XAML, мы можем поместить цветные элементы Rectangle и TextBlock в объект StackPanel.

<StackPanel Orientation="Horizontal">
    <Rectangle Width="80" Height="20">
        <Rectangle.Fill>
            <SolidColorBrush Color="Blue"/>
        </Rectangle.Fill>
    </Rectangle>
    <TextBlock Text="blue" Margin="20, 10, 0, 10"/>
</StackPanel>

Это одна из важных возможностей XAML и привязки данных. Почти каждый сложный визуальный элемент основан на шаблонах, которые можно переопределить. Чтобы использовать предыдущий элемент StackPanel в качестве шаблона, нам нужно поместить его в объект DataTemplate. DataTemplate должен определить элемент DataType, являющийся типом данных, к которым можно применять шаблон. В нашем случае это класс ColorDescriptor. Элемент DataTemplate выглядит следующим образом:

<DataTemplate x:DataType="local:ColorDescriptor">
    <!-- template content comes here -->
</DataTemplate>

Отображение данных в элементе ListBox (и во множестве других элементов управления) контролирует элемент ItemTemplate, который должен быть задан DataTemplate. Существует несколько способов это сделать. В этом уроке мы просто определим элемент DataTemplate внутри ListBox с использованием следующего синтаксиса:

<ListBox ...>
    <ListBox.ItemsSource>
        <DataTemplate ...>
            ...
        </DataTemplate>
    </ListBox.ItemsSource>
</ListBox>

Позже вы увидите, как DataTemplate можно повторно использовать в нескольких расположениях, определив его как ресурс.

Теперь весь элемент ListBox выглядит следующим образом (если вы еще не сделали этого, замените весь тег <ListBox> на следующий код XAML):

<ListBox ItemsSource="{x:Bind Logic.LotsOfColors}" 
         Margin="20" 
         Width="200"
         HorizontalAlignment="Left" 
         VerticalAlignment="Top">
    <ListBox.ItemTemplate>
        <DataTemplate x:DataType="local:ColorDescriptor">
            <StackPanel Orientation="Horizontal">
                <Rectangle Width="80" 
                           Height="20">
                    <Rectangle.Fill>
                        <SolidColorBrush Color="{x:Bind Color}"/>
                    </Rectangle.Fill>
                </Rectangle>
                <TextBlock Text="{x:Bind Name}" 
                           Margin="20, 10, 0, 10"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Обратите внимание, что, так как каждый элемент в ListBox соответствует объекту ColorDescriptor, необходимо только определить привязки внутри шаблона в контексте этого класса. Компилятор проверяет, что Logic.LotsOfColors содержит объекты ColorDescriptor и что ColorDescriptor.Color и ColorDescriptor.Name существуют и имеют правильный тип.

7. Запуск приложения

Запустите приложение, нажав клавишу F5 или выбрав Отладка/Начать отладку в меню. Список цветов должен отображаться надлежащим образом.

Screenshot that shows the Data binding Sample window, with a list of six colors next to rectangles representing the color.

Запустив приложение XAML в режиме отладки, вы сможете воспользоваться преимуществами динамического редактирования XAML. Вам даже не нужно останавливать приложение или нажимать кнопку "Сохранить". Просто измените XAML, и большая часть изменений мгновенно отразится в запущенном приложении. Попробуйте! Измените значение свойств Width и Height элемента Rectangle внутри шаблона данных на 30, тем самым превратив цветные прямоугольники в квадраты.

Screenshot that shows the Data binding Sample window, with a list of six colors next to squares representing the color.

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

Итоги

В этом уроке показаны основы отображения множества элементов в ListBox. Для этих целей подходят и другие элементы управления, например ItemsControl, ListView и GridView. Основные принципы те же самые: привязать список (IEnumerable, List<>) объектов к свойству ItemsSource и определить DataTemplates для управления отображением и поведением отдельных элементов списка. Кроме того, можно переопределить макет этих элементов и даже внешний вид самих элементов управления контейнера (но это выходит за рамки данного модуля).

Обратите внимание, что в коде отсутствует взаимодействие с самим элементом ListBox. Он просто создал коллекцию бизнес-объектов (ColorDescriptor), а среда выполнения XAML позаботилась о расширении шаблона для каждого элемента.

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

Tech logo of U W P and W P F. U W P appears dimmed.

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

1. Создание ColorDescriptor класса

Создадим класс для представления цвета. В обозревателе решений щелкните проект DatabindingSampleWPF правой кнопкой мыши, выберите Добавить/Класс и введите ColorDescriptor в качестве имени класса. Щелкните Добавить, чтобы создать класс.

ColorDescriptor содержит два свойства: сам цвет как объект System.Windows.Media.Color и имя цвета. Он также имеет конструктор, который задает эти свойства, метод, ToString() который отображает имя цвета и шестнадцатеричные значения для компонентов цвета R, G и B. Так выглядит весь класс ColorDescriptor.

using System.Windows.Media;

namespace DatabindingSampleWPF
{
    public class ColorDescriptor : ObservableObject
    {
        public ColorDescriptor(Color color, string name)
        {
            Color = color;
            Name = name;
        }

        public Color Color { get; private set; }

        public string Name { get; private set; }

        public override string ToString()
        {
            return $"{Name} (#{Color.R:X2}{Color.G:X2}{Color.B:X2})";
        }
    }
}

Замените содержимое ColorDescriptor.cs файла по умолчанию предыдущим кодом.

2. Создание страницы ColorList.xaml

Для отображения списка цветов мы будем использовать новый файл XAML. В обозревателе решений щелкните правой кнопкой мыши проект DatabindingSampleWPF и выберите Добавить/Новый элемент. Выберите Window (WPF) из списка доступных элементов и введите ColorList в качестве имени. Щелкните Добавить, чтобы создать страницу.

Screenshot of Add New Item dialog box.

3. Установка файла XAML запуска

Теперь, если вы запустите приложение, откроется область MainWindow. Потому что вы будете работать с недавно созданным ColorList.xaml, было бы приятно иметь это отображение при запуске. Чтобы это произошло, откройте App.xamlи найдите StratupUri атрибут корневого Application элемента.

StartupUri="MainWindow.xaml"

Замените MainWindow на ColorList и убедитесь, что страница ColorList появляется при запуске приложения (нажмите F5 или выберите Отладка/Начать отладку).

Screenshot that shows an empty Color List window.

4. Создание DataContext списка цветов

Мы продолжим следовать ранее представленной рекомендации по созданию отдельного класса DataContext для нового окна XAML. Итак, мы будем идти вперед и создадим новый класс, называемый ColorListDataContext.

В обозревателе решений щелкните проект DatabindingSample правой кнопкой мыши, выберите Добавить/Класс и введите ColorListDataContext в качестве имени класса. Щелкните Добавить, чтобы создать класс, и вставьте в файл следующее:

using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Windows.Media;

namespace DatabindingSampleWPF
{
    public class ColorListDataContext: ObservableObject
    {
        public List<ColorDescriptor> LotsOfColors { get; private set; }

        public ColorListDataContext()
        {
            LotsOfColors = new List<ColorDescriptor>
            {
               new ColorDescriptor(Colors.Red, "red"),
               new ColorDescriptor(Colors.White, "white"),
               new ColorDescriptor(Colors.Green, "green"),
               new ColorDescriptor(Colors.Yellow, "yellow"),
               new ColorDescriptor(Colors.Blue, "blue"),
               new ColorDescriptor(Colors.Black, "black")
            };
        }
    }
}

Класс ColorListDataContext пока очень прост. Он содержит свойство LotsOfColors, которое является элементом List объектов ColorDescriptor. Список заполняется некоторыми цветами в конструкторе класса. И это все.

5. Отображение цветов в ListBox

Следующий шаг — отображение цветов в нашем приложении. Как и раньше, необходимо создать экземпляр ColorListDataContext класса и ColorList.xamlзадать его как DataContext для всего окна. Откройте и ColorList.xamlдобавьте его сразу после тега <Window ...> :

<Window.DataContext>
    <local:ColorListDataContext/>
</Window.DataContext>

Необходимо скомпилировать код на этом этапе, чтобы конструктор XAML смог разрешить только что определенный ColorListDataContext класс.

Затем скопируйте следующую разметку <Grid> XAML в тег:

<ListBox ItemsSource="{Binding LotsOfColors}" 
         Margin="20" 
         Width="200"
         HorizontalAlignment="Left" 
         VerticalAlignment="Top"/>

Здесь интересен атрибут ItemsSource. Он предоставляет источник элементов, отображаемых в ListBox. Он также просто привязан к свойству LotsOfColors элемента ColorListDataContext.

Если вы запустите приложение сейчас, оно отобразит цвета в ListBox. Выглядит не очень хорошо. Похоже, что ListBox вызвал метод ToString() элемента ColorDescriptor, хранящегося в списке LotsOfColors.

Screenshot that shows the Color List window with six colors listed.

6. Определение шаблона для элементов

Было бы приятно иметь шаблон, показывающий фактический цвет, хранящийся в свойстве ColorDescriptor.Color и его имени. Примерно следующим образом:

Screenshot fo template.

Чтобы добавить нужный код в XAML, мы можем поместить цветные элементы Rectangle и TextBlock в объект StackPanel.

<StackPanel Orientation="Horizontal">
    <Rectangle Width="80" Height="20">
        <Rectangle.Fill>
            <SolidColorBrush Color="Blue"/>
        </Rectangle.Fill>
    </Rectangle>
    <TextBlock Text="blue" Margin="20, 10, 0, 10"/>
</StackPanel>

Это одна из важных возможностей XAML и привязки данных. Почти каждый сложный визуальный элемент основан на шаблонах, которые можно переопределить. Чтобы использовать приведенный выше StackPanel шаблон, необходимо поместить его в DataTemplate:

<DataTemplate>
    <!-- template content comes here -->
</DataTemplate>

Отображением данных в элементе ListBox (и во множестве других элементов управления) контролирует элемент ItemTemplate, который должен быть задан указанным выше элементом DataTemplate. Существует несколько способов это сделать. В этом уроке мы просто определим элемент DataTemplate внутри ListBox с использованием следующего синтаксиса:

<ListBox ...>
    <ListBox.ItemsSource>
        <DataTemplate ...>
            ...
        </DataTemplate>
    </ListBox.ItemsSource>
</ListBox>

Позже вы увидите, как DataTemplate можно повторно использовать в нескольких расположениях, определив его как ресурс.

Теперь разметка для всего ListBox выглядит следующим образом (если вы не последовали вместе, замените весь <ListBox> элемент следующим кодом XAML):

<ListBox ItemsSource="{Binding LotsOfColors}" 
         Margin="20" 
         Width="200"
         HorizontalAlignment="Left" 
         VerticalAlignment="Top">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Rectangle Width="80" 
                           Height="20">
                    <Rectangle.Fill>
                        <SolidColorBrush Color="{Binding Color}"/>
                    </Rectangle.Fill>
                </Rectangle>
                <TextBlock Text="{Binding Name}" 
                           Margin="20, 10, 0, 10"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Обратите внимание, что, так как каждый элемент в ListBox соответствует объекту ColorDescriptor, необходимо только определить привязки внутри шаблона в контексте этого класса.

7. Запуск приложения

Список цветов должен сразу отобразиться в Visual Studio. Чтобы убедиться, запустите приложение, нажав клавишу F5 или выбрав Отладка/Начать отладку в меню.

Screenshot that shows the Color List window, with six colors listed next to rectangles representing the color.

Запустив приложение XAML в режиме отладки, вы сможете воспользоваться преимуществами динамического редактирования XAML. Вам даже не нужно останавливать приложение или нажимать кнопку "Сохранить". Просто измените XAML, и большая часть изменений мгновенно отразится в запущенном приложении. Попробуйте! Измените значение свойств Width и Height элемента Rectangle внутри шаблона данных на 30, тем самым превратив цветные прямоугольники в квадраты.

Screenshot that shows the Color List window, with six colors listed next to squares representing the color.

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

Итоги

В этом уроке описаны основы отображения нескольких элементов в объекте ListBox. Для этих целей подходят и другие элементы управления, например ItemsControl, ListView и GridView. Но основные принципы одинаковы: привязать список (IEnumerable, List<>) объектов к ItemsSource свойству и определить DataTemplate способ отображения и поведения отдельных элементов списка. Кроме того, можно переопределить макет этих элементов и даже внешний вид самих элементов управления контейнера (но это выходит за рамки данного модуля).

Обратите внимание, что код логики никогда не знал о элементе ListBox управления. Он только что создал коллекцию бизнес-объектов (ColorDescriptor), а среда выполнения XAML обрабатывала отрисовку шаблона для каждого элемента.

На следующем занятии показано, как выбрать элементы из ListBox или a ComboBox, а также изменить содержимое списков из кода, чтобы добавить и удалить элементы отражаются в пользовательском интерфейсе.