Implicit Styles - cтилизируем ВСЁ
Одна из новых замечательных возможностей, которую уже можно попробовать в Silverlight 4 Beta, – это Implicit Styles. Позаимствованная из WPF, она позволяет задавать унифицированный стиль для всех элементов управления одного типа. Например, не прибегая к темам из Silverlight Toolkit, Вы можете один раз задать стиль для кнопок, текстовых полей, скроллинга, полностью стилизировав эти элементы в приложении раз и навсегда.
Что понадобится дизайнеру?
Дизайнеру для разработки понадобится установить:
Полный список инструментов смотреть тут.
С чего начать? С кнопки!
Создадим в Microsoft Expression Blend Preview for .NET 4 новый проект приложения на Silverlight 4. Возьмем небольшой набор графических элементов, который мы хотим преобразовать в стиль для кнопки. Состоит он из закругленного элемента Border и текстового блока.
<Border x:Name="Blue" HorizontalAlignment="Center" VerticalAlignment="Center" Background="#FF308899" CornerRadius="5" Padding="10,5">
<TextBlock Foreground="White" HorizontalAlignment="Center" TextWrapping="Wrap" Text="Button" VerticalAlignment="Center"/>
</Border>
А выглядит следующим образом:
Выделяем элемент Border в панели Objects & Timeline, вызываем контекстное меню и выбираем пункт “Make into control”. В появившемся диалоговом окне набираем в поиске Button, щелкаем на элемент Button, и в поле Name выбираем пункт “Apply to all” – таким образом мы будем задавать один общий стиль для всех кнопок. Также Вы можете создать новый файл ресурсов, и разместить стиль именно там.
После проделанной процедуры, в панели ресурсов можно увидеть следующее:
Появился ресурс с названием [Button default] – кликнув на который мы зайдем в режим редактирования стиля кнопки. Выполняя команду преобразования графических элементов в работающий элемент управления, Blend сделал практически всю работу за нас. Осталось немного подправить мелочи.
Собственно, мелочи…
Выделим в панели Objects & Timeline пункт Style
И зайдем в режим редактирования шаблона
В панели Objects & Timeline перетащим элемент ContentPresenter внутрь элемента Border. Если этого не сделать, то в нашем случае, кнопка может выглядеть не очень красиво – без внутренних отступов.
После того как мы переместили ContentPresenter внутрь элемента Border – кнопка выглядит так:
Ресурсы! Ресурсы! Ресурсы!
В чем можно убедиться неоднократно, так это в том, что максимально ВСЕ нужно выносить в ресурсы. Начнем мы с цветов. Как минимум один цвет у нас уже есть – фон для кнопки. Выберем наш элемент Border, для которого он используется, и в редакторе цвета нажмем на ма-а-аленький квадратик Advanced property options (в результате обсуждений Expression Community, эту кнопку-точку принято называть Property Peg).
В меню выберем пункт Convert to New Resource, зададим ключ-название для цвета, например, Blue и разместим все в том же файле ресурсов. После этого в панели ресурсов появится новый элемент, а в xaml-файле – строчка <Color x:Key="Blue">#FF308899</Color>. Заливка же фона для элемента Border преобразуется в следующую запись:
<Border.Background>
<SolidColorBrush Color="{StaticResource Blue}"/>
</Border.Background>
Состояния
Как мы знаем, в панели States можно сделать настройки для всех состояний нашей кнопки. Например, для состояния MouseOver
мы изменим цвет заливки фона кнопки. Находясь в режиме записи состояния MouseOver, на панели Objects & Timeline выберем элемент Border и, переключив обратно на редактор цвета, изменяем голубой цвет на более темный. После чего этот цвет аналогично можно добавить в ресурсы с названием, например как в нашем случае, DarkBlue.
В xaml-коде состояние MouseOver будет выглядеть так:
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" Storyboard.TargetName="Blue">
<EasingColorKeyFrame KeyTime="0" Value="{StaticResource DarkBlue}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
Аналогичные действия можно сделать и для состояния Pressed, а для Disabled – понизить прозрачность фона до 30%:
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Blue">
<EasingDoubleKeyFrame KeyTime="0" Value="0.3"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
Для состояния Focused – можно сделать границу для Border размером 1, а в качестве цвета для нее выбрать ресурс DarkBlue. Все это делается визуально в режиме записи состояния. А код получается следующим:
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderThickness)" Storyboard.TargetName="Blue">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Thickness>1</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="Blue">
<EasingColorKeyFrame KeyTime="0" Value="{StaticResource DarkBlue}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
Оптимизация – основа всего
Думаете, на этом минимальные действия над стилизацией кнопки закончены? Отнудь нет. Как мы уже выяснили – все нужно выносить в ресурсы. У нас еще остались свойства, которые можно оптимизировать.
Например, у элемента Border нашей кнопке есть два свойства, одно из которых – CornerRadius, а второе – Padding. Очень логично, что при создании следующих стилей, например, для текстового блока, скроллинга и других, Вы не будете использовать совсем новые значения для закругления углов и внутренних отступов для контента.
Поэтому выносим их тоже. Из практики, я обычно для таких свойств создаю еще один файл ресурсов - Thickness.xaml, в котором храню только отступы, толщины границ, радиусы закругления и прочие общие значения, которые удобно менять в одном файле единоразово.
После этого привязка к значениям выглядит так:
а в файле Thickness.xaml у нас есть две строчки:
<Thickness x:Key="Padding">10,5</Thickness>
<CornerRadius x:Key="CornerRadius">5</CornerRadius>
Как Вы уже догадались, эти значения можно менять через панель Resources, что, согласитесь, очень удобно.
Как применить стили?
Ну и наконец, полученный нами стиль применяется автоматом, без указания каких-либо ключей - для всех новосозданных кнопок.
Стили по ключу – в силе
Никто не отменял стили с заданием по ключу. Вы можете создавать и использовать их для отдельных элементов, которые необходимо выделить. Например, указав для нового создаваемого стиля x:Key,
<Style x:Key="CancelButton" TargetType="Button"> ...
мы можем для отдельной кнопки применить его старым методом
<Button Content="Button" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource CancelButton}"/>
