Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Windows Presentation Foundation.docx
Скачиваний:
43
Добавлен:
02.11.2018
Размер:
1.15 Mб
Скачать

17. ШАблоны элементов управления

Большинство элементов управления имеет внешний вид и поведение. Рассмотрим кнопку: её внешним видом является область для нажатия, а её поведение – это событие Click, которое вызывается в ответ на нажатие кнопки. WPF эффективно разделяет внешний вид и поведение, благодаря концепции шаблона элемента управления. Шаблон элемента управления полностью определяет визуальную структуру элемента. Шаблон переопределяем – в большинстве случаев это обеспечивает достаточную гибкость и освобождает от необходимости написания пользовательских элементов управления.

Рассмотрим создание пользовательского шаблона для кнопки. Шаблон элемента управления – это экземпляр класса System.Windows.ControlTemplate. Основным свойством шаблона является свойство VisualTree, которое содержит визуальный элемент, определяющий внешний вид шаблона. Для задания VisualTree в разметке XAML достаточно поместить в ControlTemplate дочерний элемент. В элементах управления ссылка на шаблон устанавливается через свойство Template. С учетом вышесказанного первая версия шаблона для кнопки будет описана следующей разметкой:

<Button Content="Sample" Width="100" Height="50" Padding="10">

<Button.Template>

<ControlTemplate>

<Border BorderBrush="Orange" BorderThickness="2"

CornerRadius="2" Background="Aqua"/>

</ControlTemplate>

</Button.Template>

</Button>

Рис. 43. Первая версия шаблона для кнопки.

Самый большой недостаток нашего первого шаблона заключается в том, что он не отображает содержимое кнопки (свойство Content). У шаблона может быть установлено свойство TargetType. Оно содержит тип элемента управления, являющегося целью шаблона. Если установлено свойство TargetType, при описании VisualTree для ссылки на содержимое элемента управления можно использовать объекты ContentPresenter (для элементов управления содержимым) или ItemsPresenter (для списковых элементов управления).

<Button Content="Sample" Width="100" Height="50" Padding="10">

<Button.Template>

<ControlTemplate TargetType="Button">

<Border BorderBrush="Orange" BorderThickness="2"

CornerRadius="2" Background="Aqua">

<ContentPresenter />

</Border>

</ControlTemplate>

</Button.Template>

</Button>

Рис. 44. Шаблон, отображающий содержимое кнопки.

Вторая версия шаблона не учитывает отступ, заданный на кнопке при помощи свойства Padding. Чтобы исправить это, используем привязку данных. В шаблонах допустим особый вид привязки – TemplateBinding. Эта привязка извлекает информацию из свойства элемента управления, являющегося целью шаблона1.

<Button Content="Sample" Width="100" Height="50" Padding="10">

<Button.Template>

<ControlTemplate TargetType="Button">

<Border BorderBrush="Orange" BorderThickness="2"

CornerRadius="2" Background="Aqua">

<ContentPresenter Margin="{TemplateBinding Padding}" />

</Border>

</ControlTemplate>

</Button.Template>

</Button>

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

<ControlTemplate TargetType="Button">

<Border Name="brd" BorderBrush="Orange" BorderThickness="2"

CornerRadius="2" Background="Aqua">

<ContentPresenter Margin="{TemplateBinding Padding}" />

</Border>

<ControlTemplate.Triggers>

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

<Setter TargetName="brd" Property="Background"

Value="CornflowerBlue" />

</Trigger>

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

<Setter TargetName="brd" Property="Background" Value="Blue" />

<Setter TargetName="brd" Property="BorderBrush" Value="Khaki"/>

</Trigger>

</ControlTemplate.Triggers>

</ControlTemplate>

Заметим, что, как правило, шаблоны элементов управления описываются в ресурсах окна или приложения. Часто шаблон объявляют в стиле элемента управления. Это позволяет создать эффект «шаблона по умолчанию» (в отличие от стиля, шаблон нельзя указать в ресурсах без ключа).

<Window.Resources>

<Style TargetType="Button">

<Setter Property="Template">

<Setter.Value>

<ControlTemplate TargetType="Button">

<!--содержимое шаблона не изменилось-->

</ControlTemplate>

</Setter.Value>

</Setter>

</Style>

</Window.Resources>

Наш шаблон для кнопки прост. Однако во многих случаях шаблоны выглядят сложнее. Ниже перечислены некоторые из характеристик более сложных шаблонов1:

  • Они включают элементы управления Button, которые инициируют встроенные команды или обработчики событий.

  • Они используют именованные элементы, имена у которых обычно начинаются с PART_. При создании шаблона следует проверять наличие всех этих именованных элементов, поскольку класс элемента управления может включать код, который манипулирует непосредственно этими элементами (например, присоединяет обработчики событий).

  • Они включают вложенные элементы управления, которые могут иметь свои собственные шаблоны.

  • Довольно часто они предполагают организацию элементов с помощью элемента управления Grid (хотя для более точного выравнивания различных элементов может применяться и элемент управления Canvas).

1 Это не совсем точное утверждение. Свойство содержимого Content объявлено в классе ContentControl, который является базовым для Button.

1 Последние три элемента определены в классе PropertyMetadata.

1 Можно создать отдельные потоки для отображения каждого окна, но такой дизайн встречается редко. Обычно один поток визуализирует все окна приложения.

1 Класс Window является наследником FrameworkElement.

1 Для краткости изложения полагаем, что разметка всех примеров – часть обычного окна:<Window x:Class="WpfLayout.MainWindow" Title="WPF Layout"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Height="250" Width="300">

<!-- разметка примеров -->

</Window>

1 Попытка установить одновременно Canvas.Left и Canvas.Right приведёт к игнорированию Canvas.Right. При одновременной установке Canvas.Top и Canvas.Buttom будет проигнорировано Canvas.Buttom.

1 Классы, унаследованные от UIElement, обладают булевым свойством ClipToBounds. Если в родительском элементе это свойство установлено в true, визуальное содержимое дочерних элементов отсекается при выходе за границы родителя.

1 Работа с шаблонами элементов управления и шаблонами данных рассматривается ниже.

2 Получить список всех установленных шрифтов можно с помощью статической коллекции SystemFontFamilies класса System.Windows.Media.Fonts.

1 ToolBar переопределяет визуальные стили для кнопок и разделителей. Кнопка выглядит небольшой и плоской, а разделитель – как вертикальная черта.

2 TextBlock – это не элемент управления, так как он не наследуется от Control, а является прямым наследником FrameworkElement.

1 Линия шириной 11 имеет по 5,5 единиц пространства на каждую сторону. На мониторе со стандартным разрешением такая линия выглядит как слегка расплывчатый, сглаженный контур. Чтобы убрать этот эффект, установите свойство SnapsToDevicePixels в true.

2 Для свойств Fill и Stroke изначально установлены прозрачные кисти.

1 Геометрия определяет фигуру, но без свойств отображения (таких, например, как Stroke).

1 О кривых Безье можно прочитать здесь: http://ru.wikipedia.org/wiki/Кривая_Безье.

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

1 Если цвет получен при помощи свойства класса SystemColors, приложение не сможет отследить изменение этого цвета в настройках системы во время своей работы. Если данное поведение критично, следует применить динамические ресурсы, рассматриваемые далее.

1 Если свойство LinearGradientBrush.MappingMode установить в MappingMode.Absolute, для вектора градиента будут использоваться абсолютные координаты.

2 В разметке XAML дочерние элементы <GradientStop> автоматически помещаются в коллекцию GradientStops.

1 Используется кисть<LinearGradientBrush StartPoint="0.3,0" EndPoint="0.6,0">

<GradientStop Color="AliceBlue" Offset="0" />

<GradientStop Color="Red" Offset="1" />

</LinearGradientBrush>

2 Как и для линейного градиента, по умолчанию применяется виртуальный прямоугольник, у которого левый верхний угол имеет координаты , а правый нижний – .

1 Битовые эффекты выполняются медленно. Начиная с .NET Framework 3.5 SP1 классы битовых эффектов помечены как устаревшие.

1 Если файл ресурса никак не связывался со сборкой при компиляции, можно использовать обычный URI (путь к файлу на локальной или сетевой машине, ресурс в глобальной сети).

1 Как обычно, предполагаем, что разметка примера размещена в неком окне.

1 Выражение {Binding Name} эквивалентно {Binding Path=Name}.

1 Свойство Style – это не единственное «стилевое» свойство. Класс FrameworkElement имеет свойство FocusVisualStyle – стиль, применяемый при получении фокуса ввода. Класс ItemsControl имеет свойство ItemContainerStyle – стиль, применяемый к каждому элементу списка.

1 В примере можно использовать обычный триггер свойства, ведь TextBox.Text – свойство зависимостей.

1 Каждый объект GroupStyle в коллекции ListBox.GroupStyle описывает стиль для отдельного уровня группировки.

1 Если планируется использование объекта CollectionViewSource, привязка должна выполняться непосредственно к этому объекту, а не к его свойству View.

1 Привязка {TemplateBinding prop} эквивалентна привязке{Binding RelativeSource={RelativeSource TemplatedParent}, Path=prop}

1 В составе Visual Studio имеется демонстрационный проект SimpleStyles, который предоставляет коллекцию простых, отлаженных шаблонов для всех стандартных элементов управления WPF. SimpleStyles предоставляет разработчикам отправную точку, которой они могут пользоваться для создания своих собственных шаблонов элементов управления.