Множество уровней стилей
39WPF --- Привязка, команды и стили WPF --- Множество уровней стилей
Хотя допускается определять неограниченное количество стилей на множестве различных уровней, каждый элемент WPF может использовать только один объект стиля за раз. Поначалу это может показаться ограничением, но в действительности это не так, благодаря наследованию значений свойств и наследованию стилей.
Например, предположим, что группе элементов управления требуется назначить один и тот же шрифт без применения к каждому из них одного и того же стиля. В этом случае можно разместить нужные элементы управления в одной панели (или в контейнере другого типа) и установить стиль контейнера. При условии установки свойств, которые используют средство наследования значений, эти значения будут передаваться дочерним элементам. К числу свойств, которые поддерживают такую модель, относятся IsEnabled, IsVisible, Foreground и все свойства, связанные со шрифтом.
В других ситуациях требуется создать стиль, основанный на другом стиле. Для использования наследования стилей необходимо установить атрибут BasedOn соответствующего стиля. Например, рассмотрим два следующих стиля:
<Style x:Key="MyButtonStyle">
<Setter Property="Control.FontFamily" Value="Calibri"></Setter>
<Setter Property="Control.FontSize" Value="18"></Setter>
<Setter Property="Control.FontWeight" Value="Bold"></Setter>
<Setter Property="Control.Padding" Value="5"></Setter>
<Setter Property="Control.Margin" Value="5"></Setter>
</Style>
<Style x:Key="TiledStyle" BasedOn="{StaticResource MyButtonStyle}">
<Setter Property="Control.Background">
<Setter.Value>
<ImageBrush TileMode="Tile" ViewportUnits="Absolute"
Viewport="0 0 32 32" ImageSource="cry.png"
Opacity="0.3"></ImageBrush>
</Setter.Value>
</Setter>
</Style>
Первый стиль (MyButtonStyle) определяет три свойства шрифта и два свойства для отступов. Второй стиль (TiledStyle) получает их от MyButtonStyle и затем дополняет свойством, которое изменяет кисти фона. Такое состоящее из двух частей проектное решение предоставляет возможность применять одни только настройки шрифта либо комбинацию настроек шрифта и цвета. Это решение также позволяет создавать больше стилей, включающих в себя уже определенные детали шрифта или цвета (причем не обязательно вместе).
Свойство BasedOn можно использовать для создания целой цепочки унаследованных стилей. Главное помнить о том, что в случае установки одного и того же свойства дважды, последнее средство установки этого свойства (из производного класса, находящегося дальше всех в цепочке наследования) будет переопределять любые более ранние определения.
На рисунке показан пример работы наследования стилей в простом окне, использующем оба стиля:
Хотя наследование стилей на первый взгляд выглядит очень удобным приемом, обычно оно не стоит затрачиваемых усилий. Причина в том, что наследование стилей влечет за собой те же проблемы, что и наследование кода, т.е. приводит к образованию зависимостей, которые делают приложение более хрупким. Например, в случае использования приведенной выше разметки одни и те же характеристики шрифта обязательно должны сохраняться для обоих стилей. Модификация стиля MyButtonStyle приводит также к изменению стиля TiledStyle — если только явно не добавить дополнительные средства установки, переопределяющие унаследованные значения.
Эта проблема тривиальна в примере с двумя стилями, но существенно усложняется при наследовании стилей в реальных приложениях. Обычно стили делятся на категории на основе типов содержимого и ролей, которые это содержимое исполняет. Например, приложение для продаж может включать в себя стили наподобие ProductTitleStyle, ProductTextStyle, HighlightQuoteStyle, NavigationButtonStyle и т.д. Если основать стиль ProductTitleStyle на ProductTextStyle (возможно потому, что они оба разделяют один и тот же шрифт), то возникнут проблемы, когда позже понадобится применить к стилю ProductTextStyle настройки, которые не должны применяться к стилю ProductTitleStyle (например, разные поля). В таком случае придется определить эти настройки в стиле ProductTextStyle и явно переопределить их в стиле ProductTitleStyle. В конечном итоге это приведет к получению гораздо более сложной модели и весьма небольшому количеству настроек, которые действительно используются многократно.
Не имея веских причин основывать один стиль на другом (например, если второй стиль является просто особым случаем первого и предусматривает изменение всего лишь нескольких характеристик из огромного количества унаследованных настроек), наследование стилей лучше не использовать.