Привязка данных и списки
До сих пор привязка данных использовалась только для отображения и редактирования свойств одного объекта. На этом занятии вы примените концепции привязки данных для отображения коллекции объектов. Чтобы упростить задачу, этими объектами будут цвета. В частности, это будут несколько экземпляров класса 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
в качестве имени. Щелкните Добавить, чтобы создать страницу.
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
.
6. Определение шаблона для элементов
Было бы приятно иметь шаблон, показывающий фактический цвет, хранящийся в свойстве ColorDescriptor.Color
, и его имя. Примерно следующим образом:
Чтобы добавить нужный код в 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 или выбрав Отладка/Начать отладку в меню. Список цветов должен отображаться надлежащим образом.
Запустив приложение XAML в режиме отладки, вы сможете воспользоваться преимуществами динамического редактирования XAML. Вам даже не нужно останавливать приложение или нажимать кнопку "Сохранить". Просто измените XAML, и большая часть изменений мгновенно отразится в запущенном приложении. Попробуйте! Измените значение свойств Width
и Height
элемента Rectangle
внутри шаблона данных на 30, тем самым превратив цветные прямоугольники в квадраты.
Это называется XAML Горячая перезагрузка, и это может быть полезно для точной настройки макета и анимации в приложении.
Итоги
В этом уроке показаны основы отображения множества элементов в ListBox
. Для этих целей подходят и другие элементы управления, например ItemsControl
, ListView
и GridView
. Основные принципы те же самые: привязать список (IEnumerable
, List<>
) объектов к свойству ItemsSource
и определить DataTemplates
для управления отображением и поведением отдельных элементов списка. Кроме того, можно переопределить макет этих элементов и даже внешний вид самих элементов управления контейнера (но это выходит за рамки данного модуля).
Обратите внимание, что в коде отсутствует взаимодействие с самим элементом ListBox
. Он просто создал коллекцию бизнес-объектов (ColorDescriptor
), а среда выполнения XAML позаботилась о расширении шаблона для каждого элемента.
В следующем уроке показано, как выбрать элементы из ListBox
или раскрывающегося списка и изменить содержимое списков из кода, чтобы добавление и удаление элементов отражалось в пользовательском интерфейсе.
До сих пор привязка данных использовалась только для отображения и редактирования свойств одного объекта. На этом занятии вы примените концепции привязки данных для отображения коллекции объектов. Чтобы упростить задачу, этими объектами будут цвета. В частности, они будут несколькими экземплярами 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
в качестве имени. Щелкните Добавить, чтобы создать страницу.
3. Установка файла XAML запуска
Теперь, если вы запустите приложение, откроется область MainWindow. Потому что вы будете работать с недавно созданным ColorList.xaml
, было бы приятно иметь это отображение при запуске. Чтобы это произошло, откройте App.xaml
и найдите StratupUri
атрибут корневого Application
элемента.
StartupUri="MainWindow.xaml"
Замените MainWindow
на ColorList
и убедитесь, что страница ColorList появляется при запуске приложения (нажмите F5 или выберите Отладка/Начать отладку).
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
.
6. Определение шаблона для элементов
Было бы приятно иметь шаблон, показывающий фактический цвет, хранящийся в свойстве ColorDescriptor.Color
и его имени. Примерно следующим образом:
Чтобы добавить нужный код в 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 или выбрав Отладка/Начать отладку в меню.
Запустив приложение XAML в режиме отладки, вы сможете воспользоваться преимуществами динамического редактирования XAML. Вам даже не нужно останавливать приложение или нажимать кнопку "Сохранить". Просто измените XAML, и большая часть изменений мгновенно отразится в запущенном приложении. Попробуйте! Измените значение свойств Width
и Height
элемента Rectangle
внутри шаблона данных на 30, тем самым превратив цветные прямоугольники в квадраты.
Это называется XAML Горячая перезагрузка, и это может быть полезно для точной настройки макета и анимации в приложении.
Итоги
В этом уроке описаны основы отображения нескольких элементов в объекте ListBox
. Для этих целей подходят и другие элементы управления, например ItemsControl
, ListView
и GridView
. Но основные принципы одинаковы: привязать список (IEnumerable
, List<>
) объектов к ItemsSource
свойству и определить DataTemplate
способ отображения и поведения отдельных элементов списка. Кроме того, можно переопределить макет этих элементов и даже внешний вид самих элементов управления контейнера (но это выходит за рамки данного модуля).
Обратите внимание, что код логики никогда не знал о элементе ListBox
управления. Он только что создал коллекцию бизнес-объектов (ColorDescriptor
), а среда выполнения XAML обрабатывала отрисовку шаблона для каждого элемента.
На следующем занятии показано, как выбрать элементы из ListBox
или a ComboBox
, а также изменить содержимое списков из кода, чтобы добавить и удалить элементы отражаются в пользовательском интерфейсе.