Расширение разметки

28

Рассматриваемый ранее шаблон можно применять только к элементам управления типа Button, и поэтому имеет смысл установить его свойства в элементе разметки <Button> таким образом, чтобы шаблон проявлял себя особым образом. В частности свойство Fill элемента управления типа Ellipse жестко закодировано на голубой цвет, тогда как свойство Content элемента управления типа Label - на строковое значение "ОК!", но ведь в пользовательском интерфейсе нужны кнопки разного цвета и разные текстовые надписи меток, поэтому можно попытаться определить следующие кнопки в главном окне приложения, представленного объектом типа Window:

<Button Height="100" Width="100" Content="OK!" ...
		<Button Content="Start" ...
		<Button Content="Stop" ...

Но, несмотря на то, что каждый объект типа Button определен и настроен на применение особого цвета фона и текстовой надписи в свойствах Background и Content, все три кнопки по-прежнему имеют голубой цвет фона и текстовую надпись ОК!. Дело в том, что свойства элементов управления типа Button, в которых применяется данный шаблон, не совпадают в точности со свойствами, задаваемыми в самом шаблоне, например, со свойством Fill элемента управления типа Ellipse. А значение свойства Content элемента управления типа Label, определенное в области действия элемента разметки <Button>, не направляется автоматически к внутреннему потомку шаблона.

Подобные затруднения могут быть разрешены с помощью расширения разметки {TemplateBinding} при построении специального шаблона. Это дает возможность захватывать значения свойств, определенных в элементе управления с помощью шаблона, чтобы использовать их для установки свойств в самом шаблоне.

Ниже приведен переработанный вариант разметки шаблона RoundButtonTemplate, в котором расширение разметки (TemplateBinding) теперь используется для привязки свойства Background элемента управления типа Button к свойству Fill элемента управления типа Ellipse:

<Ellipse x:Name="buttonSurface" Fill="{TemplateBinding Background}"/>
<Label x:Name="buttonCaption" VerticalAlignment="Center"
		HorizontalAlignment="Center"
		FontWeight="Bold" FontSize="20" Content="{TemplateBinding Content}"/>

После такого обновления можно создать кнопки с разными цветами фона и текстовыми надписями:

Использование привязок шаблона

Представление о назначении элемента разметки <ContentPresenter>

При разработке рассматриваемого здесь шаблона элемент управления Label был выбран для отображения текстовой надписи на кнопке. У этого элемента управления имеется такое же свойство, как и у элемента управления типа Button. Поэтому с помощью расширения разметки {TemplateBinding} можно определить элемент управления типа Button с более сложным содержимым, чем простая текстовая строка. В качестве примера ниже показана кнопка со сложным содержимым, описываемым в приведенной ниже разметке:

<ListBox Height="60" Width="60">
				<ListBoxItem Content="Hello"></ListBoxItem>
				<ListBoxItem Content="Hello"></ListBoxItem>
				<ListBoxItem Content="Hello"></ListBoxItem>
				<ListBoxItem Content="Hello"></ListBoxItem>
				<ListBoxItem Content="Hello"></ListBoxItem>
				<ListBoxItem Content="Hello"></ListBoxItem>
				<ListBoxItem Content="Hello"></ListBoxItem>
</ListBox>
Кнопка со сложным содержимым

Данный конкретный элемент управления выглядит внешне и действует так, как и предполагалось. Но что, если требуется передать его сложное содержимое компоненту шаблона, не имеющему свойства Content? Когда в шаблоне требуется определить обобщенную область отображения содержимого, то для этой цели можно воспользоваться элементом разметки класса <ContentPresenter> вместо того, чтобы указывать конкретный тип элемента управления (Label или TextBlock).

И хотя этого не требуется в рассматриваемом здесь примере проекта, ниже приведена разметка, в которой показано, каким образом можно создать специальный шаблон, в котором элемент разметки <ContentPresenter> используется для отображения конкретного значения свойства Content элемента управления по заданному шаблону:

<ContentPresenter x:Name="buttonCaption" HorizontalAlignment="Center" VerticalAlignment="Center" />

Внедрение шаблонов в стили

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

По желанию можете встроить шаблон в более крупный стиль. Это даст возможность присвоить значения различным свойствам элемента управления целевого типа, а также определить его особый внешний вид. Ниже приведен окончательный вариант разметки расматриваемого здесь шаблона, который теперь встроен в стиль оформления кнопок. Обратите внимание на то, что в элементе разметки <ControlTemplate> удален атрибут х:Key, а вместо этого в элемент разметки <Style> добавлен стиль:

<!-- Стиль, содержащий шаблон -->
		<Style x:Key="RoundButtonStyle" TargetType="Button">
			<Setter Property="Height" Value="100"></Setter>
			<Setter Property="Width" Value="100"></Setter>
			<Setter Property="FontSize" Value="14"></Setter>
			<Setter Property="Template" Value="{StaticResource RoundButtonTemplate}"></Setter>
		</Style>

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

Пройди тесты
Лучший чат для C# программистов