| Предыдущая лекция | Следующая лекция | |
|---|---|---|
| Поиск, сортировка | Содержание | Стили, триггеры и темы |
В реальных проектах DataGrid используется редко. Обычно используется компонент ListBox. Пример из задания одного из прошедших демо-экзаменов:
Вверху уже знакомый нам WrapPanel, а вот основная информация выводится в виде блоков
Для создания такого макета используется элемент ListBox
В разметке вместо DataGrid вставляем ListBox:
<ListBox
Grid.Row="1"
Background="White"
ItemsSource="{Binding catList}"
>
<!--
сюда потом вставить ListBox.ItemTemplate
-->
</ListBox>
Внутри него вставляем шаблон для элемента списка (ListBox.ItemTemplate): пока у нас только прямоугольная рамка со скруглёнными углами (в этом макете вроде скрулять не надо, возможно осталось от другого шаблона)
<ListBox.ItemTemplate>
<DataTemplate>
<Border
BorderThickness="1"
BorderBrush="Black"
CornerRadius="5"
>
<!-- сюда потом вставить содержимое: grid из трёх колонок -->
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
Внутри макета вставляем Grid из трёх колонок: для картинки, основного содержимого и ещё чего-нибудь.
<Grid
Margin="10"
HorizontalAlignment="Stretch"
>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="64"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<!-- сюда потом вставить колонки -->
</Grid>
В первой колонке выводим изображение:
<Image
Width="64"
Height="64"
Source="{Binding imageBitmap,TargetNullValue={StaticResource defaultImage}}" />
Обратите внимание, в классе Cat нет поля imageBitmap. Для получения картинки я использую вычисляемое свойство imageBitmap - в геттере проверяю есть ли такая картинка, т.к. наличие названия в модели не означает наличие файла на диске. Если файла нет, то возвращается null и рисуется картинка по-умолчанию, которую надо зашить в ресурсы приложения.
В реальных проектах, конечно, изображения получают с сервера, но на демо-экзамене на реализацию этого функционала времени нет, поэтому картинки кладутся в каталог с проектом (не в ресурсы, а в каталог с исполняемым файлом). Нам нужно найти картинки для нашей предметной области и добавить в поле photo
Добавьте в класс Cat вычисляемое свойство:
public class Cat
{
...
public Uri? imageBitmap {
get {
var imageName = Environment.CurrentDirectory + "/img/" + (photo ?? "");
return System.IO.File.Exists(imageName) ? new Uri(imageName) : null;
}
}
}
Что здесь происходит?
Environment.CurrentDirectory возвращает путь к исполняемому файлу, т.е. что-то типа <путь к проекту>/bin/debug/net-8img, т.е. все ваши картинки должны быть в этом подкаталогеphoto (его надо добавить в модель и в поставщике данных заполнить названиями существующих файлов изображений)Изображение по-умолчанию задается в ресурсах окна. Но в принципе можно их задать и в элементе ListBox, т.к. в других элементах это изображение не используется.
<Window.Resources>
<BitmapImage
x:Key='defaultImage'
UriSource='./Images/picture.png' />
</Window.Resources>
тут, как раз, указывается путь к изображению в ресурсах (в моём случае в приложении создан каталог Images)
Во второй колонке вывожу основную информацию о кошке: кличку и породу.
Так как данные выводятся в несколько строк, то заворачиваю их в StackPanel (тут можно использовать и Grid, но их и так уже много в разметке)
<StackPanel
Grid.Column="1"
Margin="5"
Orientation="Vertical">
<TextBlock
Text="{Binding name}"/>
<TextBlock
Text="{Binding breed.title}"/>
</StackPanel>
В третьей колонке выводим возраст
<TextBlock
Grid.Column="2"
Text="{Binding age}"/>
На данный момент приложение должно выглядеть примерно так (я поле photo не заполнил, поэтому у всех заглушка по-умолчанию)
Видно, что размер элемента зависит от содержимого.
Чтобы это исправить нужно добавить в ListBox стиль для элемента контейнера, в котором задать горизонтальное выравнивание по ширине:
<ListBox
Grid.Row="1"
Grid.Column="1"
ItemsSource="{Binding ProductList}"
>
<ListBox.ItemContainerStyle>
<Style
TargetType="ListBoxItem">
<Setter
Property="HorizontalContentAlignment"
Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
...
Теперь окно должно выглядеть как положено:
Такое задание было на одном из прошлых чемпионатов, вполне вероятно что появится и на демо-экзамене.
Компоненты ListBox и ListView по умолчанию инкапсулируют все элементы списка в специальную панель VirtualizingStackPanel, которая располагает все элементы по вертикали. Но с помощью свойства ItemsPanel можно переопределить тип панели элементов внутри списка.
Мы будем использовать уже знакомую вам WrapPanel:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel
HorizontalAlignment="Center"
ItemsWidth="200"
/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
Атрибут HorizontalAlignment используем, чтобы "плитки" центрировались.
Как видим, элементы отображаются горизонтальным списком, но нет переноса. Для включения переноса элементов нужно в ListBox отключить горизонтальный скролл, добавив атрибут ScrollViewer.HorizontalScrollBarVisibility="Disabled":
Свойство ItemContainerStyle уже не нужно и его можно убрать.
Размеры наших элементов по-прежнему зависят от содержимого - тут надо править шаблон (ширина элемента Grid в DataTemplate).
Итоговая разметка для вывода "плиткой" должна выглядеть примерно так:
<ListBox
ItemsSource="{Binding catList}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel
HorizontalAlignment="Center" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
...
| Предыдущая лекция | Следующая лекция | |
|---|---|---|
| Поиск, сортировка | Содержание | Стили, триггеры и темы |