Установка свойств стилей

78

Как было показано ранее, любой объект Style умещает в себе коллекцию объектов Setter. Каждый объект Setter устанавливает одно свойство в элементе. Единственное ограничение состоит в том, что объект Setter может изменять только свойство зависимости — другие свойства не могут быть модифицированы.

В некоторых случаях значение свойства не может устанавливаться с использованием простой строки атрибута. Например, объект ImageBrush нельзя создать с помощью простой строки. В такой ситуации должен применяться уже знакомый трюк с XAML-разметкой, который заключается в замещении атрибута вложенным элементом, например:

<Style x:Key="TiledStyle">
            <Setter Property="Control.Background">
                <Setter.Value>
                    <ImageBrush TileMode="FlipXY" ViewportUnits="Absolute"
                                Viewport="0 0 32 32" ImageSource="cry.png"
                                Opacity="0.4"></ImageBrush>
                </Setter.Value>
            </Setter>
</Style>

Если нужно повторно использовать одну и ту же кисть изображения в более чем одном стиле (или в более чем одном объекте Setter того же самого стиля), можно определить его как ресурс, который затем применять внутри стиля.

Чтобы идентифицировать свойство, которое должно устанавливаться, необходимо предоставить имя класса и имя свойства. Имя класса, однако, не обязательно должно представлять тот класс, в котором данное свойство определено. Это может быть имя производного класса, который наследует свойство. Например, взгляните на следующую версию стиля BigFontButton, в которой ссылки на класс Control заменяются ссылками на класс Button:

<Style х:Key="BigFontButtonStyle">
   <Setter Property="Button.FontFamily" Value="Times New Roman" />
   <Setter Property="Button.FontSize" Value="18" />
   <Setter Property="Button.FontWeight" Value="Bold" />
</Style>

Если подставить этот стиль в примере, который был разобран в предыдущей статье, результат окажется тем же. В чем тогда разница? В данном случае разница состоит в способе обработки средой WPF других классов, которые могут включать те же самые свойства FontFamily, FontSize и FontWeight, но не наследоваться от Button. Например, если применить эту версию стиля BigFontButton к элементу управления Label, ничего не произойдет. WPF просто проигнорирует эти три свойства, поскольку к Label они неприменимы. Но если используется исходный стиль, то связанные со шрифтом свойства окажут влияние на элемент управления Label, потому что класс Label унаследован от Control.

Факт игнорирования WPF неприменимых свойств означает возможность установки свойств, которые необязательно будут доступны в элементе, к которому применяется стиль. Например, если установлено свойство ButtonBase.IsCancel, оно будет вступать в силу только в случае установки стиля для кнопки.

В WPF имеется несколько случаев определения одних и тех же свойств в более чем одном месте в иерархии элементов. Например, весь набор свойств шрифтов (вроде свойства FontFamily) определен как в классе Control, так и в классе TextBlock. Если создается стиль, который применяется к объектам TextBox и элементам, унаследованным от Control, может появиться идея записать разметку следующим образом:

<Style х:Key="BigFontStyle">
   <Setter Property="Button.FontFamily" Value="Times New Roman" />
   <Setter Property="Button.FontSize" Value="18" />
   
   <Setter Property="TextBlock.FontFamily" Value="Arial" />
   <Setter Property="TextBlock.FontSize" Value="10" />
</Style>

Однако это не даст желаемого эффекта. Проблема в том, что хотя свойства Button.FontFamily и TextBlock.FontFamily объявлены отдельно в соответствующих им базовых классах, оба они являются ссылками на одно и то же свойство зависимости. (Другими словами, свойства TextBlock.FontSizeProperty и Control.FontSizeProperty являются ссылками, которые указывают на один и тот же объект DependencyProperty). В результате при использовании данного стиля WPF будет устанавливать свойство FontFamily и FontSize дважды.

Параметры, применяемые последними (в рассматриваемом случае это шрифт Arial размером в 10 единиц), получают преимущество и применяются к обоим объектам, Button и TextBlock. Хотя эта проблема весьма специфична и для многих свойств никогда не возникает, важно не забывать о ней при создании стилей, которые применяют разное форматирование к различным типам элементов.

Существует еще один прием, которым можно пользоваться для упрощения объявлений стилей. Если все свойства предназначены для элементов одного и того же типа, можно установить свойство TargetType объекта Style для указания класса, к которому будут применяться эти свойства. Например, создать стиль, предназначенный только для кнопок, можно следующим образом:

<Style х:Кеу="BigFontButtonStyle" TargetType="Button">
   <Setter Property="FontFamily" Value="Times New Roman" />
   <Setter Property="FontSize" Value="18" />
   <Setter Property="FontWeight" Value="Bold" />
</Style>

Это относительно небольшое удобство. Как будет показано позже, свойство TargetType может также дублироваться в виде сокращения, что позволяет применять стили автоматически, если ключевое имя стиля опущено.

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