Настройка внешнего вида списков

Класс ItemsControl обладает набором свойств, позволяющих гибко настроить внешний вид любого списка:

Template – шаблон списка как элемента управления. Чтобы отображать данные, помещённые в список, шаблон должен содержать ItemsPresenter или контейнер компоновки, у которого свойство IsItemsHost равно true.

ItemsPanel – контейнер компоновки для элементов списка.

ItemContainerStyle – стиль контейнера, обрамляющего элемент списка.

ItemContainerStyleSelector – объект класса-наследника StyleSelector с методом выбора стиля для ItemContainerStyle.

ItemTemplate – шаблон данных, используемый для отображения отдельного элемента списка.

ItemTemplateSelector – объект класса-наследника DataTemplateSelector с методом выбора шаблона для ItemTemplate.

Рис 48. Структура списка.

Если у списка установлено свойство ItemsContainerStyle, то он передаст этот стиль каждому своему элементу при его создании (в случае ListBox каждый элемент – это объект ListBoxItem). Ниже показана разметка и эффект применения ItemsContainerStyle для списка. Обратите внимание на триггер, срабатывающий при выделении элемента.

<!-- помещаем стиль в ресурсы окна -->

<Window.Resources>

<!-- этот ресурс нужен для изменения цвета выбранного элемента -->

<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"

Color="DarkRed" />

<Style x:Key="normal" TargetType="ListBoxItem">

<Setter Property="Background" Value="LightSteelBlue" />

<Setter Property="Margin" Value="3" />

<Setter Property="Padding" Value="3" />

<Style.Triggers>

<Trigger Property="IsSelected" Value="True">

<Setter Property="FontSize" Value="14" />

<Setter Property="FontWeight" Value="Bold" />

</Trigger>

</Style.Triggers>

</Style>

</Window.Resources>

<!-- изменения в описании ListBox -->

<ListBox Name="lst" DisplayMemberPath="Name" Width="200"

ItemContainerStyle="{StaticResource normal}" />

Рис. 49. Список с установленным свойством ItemContainerStyle.

При помощи селекторов стилей реализуется возможность менять стиль элемента списка на основе элемента данных. Селектор стилей – класс, унаследованный от StyleSelector, с перекрытым методом SelectStyle(). Для рассматриваемого примера создадим селектор стилей, выделяющий «агентов».

public class AgentStyleSelector: StyleSelector

{

public Style NormalStyle { get; set; }

public Style AgentStyle { get; set; }

public override Style SelectStyle(object item,

DependencyObject container)

{

var person = (Person) item;

return person.Name.StartsWith("Agent")? AgentStyle:

NormalStyle;

}

}

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

<Window.Resources>

<!-- стили простые, без триггеров -->

<Style x:Key="normal" TargetType="ListBoxItem">

<Setter Property="Background" Value="LightSteelBlue" />

<Setter Property="Margin" Value="3" />

<Setter Property="Padding" Value="3" />

</Style>

<Style x:Key="agent" TargetType="ListBoxItem">

<Setter Property="Background" Value="Aqua" />

<Setter Property="Margin" Value="3" />

<Setter Property="Padding" Value="3" />

</Style>

</Window.Resources>

<!-- настройка ListBox -->

<ListBox Name="lst" DisplayMemberPath="Name" Width="200">

<ListBox.ItemContainerStyleSelector>

<WpfLists:AgentStyleSelector

NormalStyle="{StaticResource normal}"

AgentStyle="{StaticResource agent}" />

</ListBox.ItemContainerStyleSelector>

</ListBox>

Рис. 50. Селектор стилей в действии.

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

StyleSelector selector = lst.ItemContainerStyleSelector;

lst.ItemContainerStyleSelector = null;

lst.ItemContainerStyleSelector = selector;

Можно организовать запуск этого кода автоматически в ответ на определённые изменения, обрабатывая такие события, как PropertyChanged (объявлено в INotifyPropertyChanged) или Binding.SourceUpdated.

Изменить состав отображаемой в элементе списка информации помогают шаблоны данных. Для установки шаблона данных можно использовать свойство списка ItemTemplate или свойство шаблона DataTemplate (глобальный шаблон). У списка также имеется свойство ItemTemplateSelector для задания селектора шаблонов (работает так же, как и селектор стилей).

// селектор шаблона данных

public class AgentTemplateSelector: DataTemplateSelector

{

public DataTemplate NormalTemplate { get; set; }

public DataTemplate AgentTemplate { get; set; }

public override DataTemplate SelectTemplate(object item,

DependencyObject container)

{

var person = item as Person;

return person == null? null:

(person.Name.StartsWith("Agent")? AgentTemplate:

NormalTemplate);

}

}

<!-- описание шаблонов данных в ресурсах -->

<Window.Resources>

<DataTemplate x:Key="normal">

<Border Width="170" BorderBrush="Blue" BorderThickness="1"

CornerRadius="2" Padding="3" Margin="3">

<StackPanel>

<TextBlock FontSize="12" FontWeight="Bold"

Text="{Binding Name}" />

<TextBlock Text="{Binding Age}" />

</StackPanel>

</Border>

</DataTemplate>

<DataTemplate x:Key="agent">

<Border Width="170" BorderBrush="Red" BorderThickness="3"

CornerRadius="2" Padding="3" Margin="3">

<TextBlock FontSize="16" FontWeight="Bold"

Text="{Binding Name}" />

</Border>

</DataTemplate>

</Window.Resources>

<!-- настройка ListBox для использования шаблонов данных -->

<ListBox Name="lst" Width="200">

<ListBox.ItemTemplateSelector>

<WpfLists:AgentTemplateSelector

NormalTemplate="{StaticResource normal}"

AgentTemplate="{StaticResource agent}" />

</ListBox.ItemTemplateSelector>

</ListBox>

Рис. 51. Список с шаблонами данных.

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

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

<!-- показана только настройка свойства ItemsPanel -->

<ListBox Name="lst" Width="400"

ScrollViewer.HorizontalScrollBarVisibility="Disabled">

<ListBox.ItemsPanel>

<ItemsPanelTemplate>

<WrapPanel />

</ItemsPanelTemplate>

</ListBox.ItemsPanel>

</ListBox>

Рис. 52. Изменение контейнера компоновки элементов.

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


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: