- Styles (Стилі ) – представляють простий механізм стилізації шляхом застосування набору значень пропертей для більш ніж одного елемента. Функціонал подібний до використання CSS в HTML;
- Templates (Темплейти) – використовуються для зміни вигляду контролу, визначають візуальне представлення контролу;
- Skins (Скіни) - представляють собою специфічні колекції стилів і / або темплейтів , зазвичай з можливістю бути зміненими динамічно.
- Themes (Теми) - механізм, який дозволяє використовувати візуальні характеристики операційної системи, з можливістю змін налаштування юзером.
В дану пості будуть розглядатись Скіни і Теми.
Skinning
Skinning полягає в механізмі динамічної зміни зовнішнього вигляду аплікації (або скіна ). Skin являє собою специфічні колекції стилів і / або темплейтів , зазвичай з можливістю бути зміненими динамічно.В WPF немає чіткої концепції яка називається skin, і немає формального понняття skin.
Можна легко написати аплікацію або компонент, який підтримує skinning за допомогою механізму Dynamic Resource в WPF
Давайте розглянемо кроки для скіннінгу аплікації.
- Створення логічно повязаних стилів і темплейтів для UI елементів і розміщення їх в ResourceDictionary.
1: <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
3: <!--Brushes-->
4: <LinearGradientBrush x:Key="BlueBackground"
5: StartPoint="0,0"
6: EndPoint="0,1">
7: <GradientStop Offset="0"
8: Color="#c1dbe8" />
9: <GradientStop Offset="0.5"
10: Color="#008fc7" />
11: <GradientStop Offset="1"
12: Color="#066caa" />
13: </LinearGradientBrush>
14:
15: <SolidColorBrush x:Key="BlueStroke"
16: Color="#0075b0" />
17:
18: <ImageBrush x:Key="BluePattern"
19: ImageSource="/Images/line6.png"
20: TileMode="Tile"
21: Viewport="0,0,100,100"
22: ViewportUnits="Absolute" />
23:
24: <!--Control Templates-->
25: <ControlTemplate x:Key="LabelTemplate"
26: TargetType="Label">
27: <Border BorderBrush="{StaticResource BlueStroke}"
28: BorderThickness="1"
29: Background="White"
30: CornerRadius="3,15,15,3"
31: Padding="1">
32: <Border Background="{StaticResource BlueBackground}"
33: CornerRadius="3,15,15,3"
34: Padding="3">
35: <ContentPresenter />
36: </Border>
37: </Border>
38: </ControlTemplate>
39:
40: <ControlTemplate x:Key="ButtonTemplate"
41: TargetType="Button">
42: <Grid>
43: <Border x:Name="Border"
44: Background="{StaticResource BlueBackground}"
45: BorderThickness="1"
46: CornerRadius="3"
47: BorderBrush="{StaticResource BlueStroke}"
48: RenderTransformOrigin="0.5,0.5" />
49: <ContentPresenter VerticalAlignment="Center"
50: HorizontalAlignment="Center"
51: TextElement.Foreground="White" />
52: </Grid>
53:
54: <ControlTemplate.Triggers>
55: <Trigger Property="IsPressed"
56: Value="True">
57: <Setter Property="RenderTransform"
58: TargetName="Border">
59: <Setter.Value>
60: <ScaleTransform ScaleX="1"
61: ScaleY="-1" />
62: </Setter.Value>
63: </Setter>
64: </Trigger>
65: <Trigger Property="IsMouseOver"
66: Value="True">
67: <Setter Property="BorderBrush"
68: TargetName="Border"
69: Value="#a1bbc8" />
70: </Trigger>
71: </ControlTemplate.Triggers>
72: </ControlTemplate>
73:
74: <!--Styles-->
75: <Style x:Key="LabelStyle"
76: TargetType="Label">
77: <Setter Property="Foreground"
78: Value="White" />
79: <Setter Property="Template"
80: Value="{StaticResource LabelTemplate}" />
81: <Setter Property="Width"
82: Value="100" />
83: <Setter Property="VerticalAlignment"
84: Value="Top" />
85: <Setter Property="Margin"
86: Value="0,0,8,0" />
87: </Style>
88:
89: <Style x:Key="TextBoxStyle"
90: TargetType="TextBox">
91: <Setter Property="BorderBrush"
92: Value="{StaticResource BlueStroke}" />
93: <Setter Property="Foreground"
94: Value="{StaticResource BlueStroke}" />
95: <Setter Property="FontSize"
96: Value="13" />
97: </Style>
98:
99: <Style x:Key="PasswordBoxStyle"
100: TargetType="PasswordBox">
101: <Setter Property="BorderBrush"
102: Value="{StaticResource BlueStroke}" />
103: <Setter Property="Foreground"
104: Value="{StaticResource BlueStroke}" />
105: <Setter Property="FontSize"
106: Value="13" />
107: </Style>
108:
109: <Style x:Key="ButtonStyle"
110: TargetType="Button">
111: <Setter Property="Template"
112: Value="{StaticResource ButtonTemplate}" />
113: <Setter Property="HorizontalAlignment"
114: Value="Right" />
115: </Style>
116:
117: <Style x:Key="BorderStyle"
118: TargetType="Border">
119: <Setter Property="Padding"
120: Value="10" />
121: <Setter Property="Background"
122: Value="Blue" />
123: </Style>
124:
125: <Style TargetType="{x:Type RadioButton}" >
126: <Setter Property="Template">
127: <Setter.Value>
128: <ControlTemplate TargetType="{x:Type RadioButton}">
129: <BulletDecorator Background="White" Cursor="Hand">
130: <BulletDecorator.Bullet>
131: <Grid Height="16" Width="16">
132: <!--Define size of the Bullet-->
133:
134: <!--The two borders-->
135: <Border Name="RadioOuter" Background="Transparent" BorderBrush="Gainsboro" BorderThickness="2" CornerRadius="2" />
136: <Border CornerRadius="0" Margin="4" Name="RadioMark" Background="#FFADADAD" Visibility="Hidden" />
137:
138: </Grid>
139: </BulletDecorator.Bullet>
140:
141: <!--Text element-->
142: <TextBlock Margin="3,1,0,0" Foreground="#FF3E3E3E" FontFamily="Calibri" FontSize="12">
143: <ContentPresenter />
144: </TextBlock>
145: </BulletDecorator>
146:
147: <!--If item is checked, trigger the visibility of the mark-->
148: <ControlTemplate.Triggers>
149: <Trigger Property="IsChecked" Value="true">
150:
151: <!--If item is checked, trigger the visibility of the mark
152: and change the color of the selected bullet into a darker gray for better highlighting-->
153: <Setter TargetName="RadioMark" Property="Visibility" Value="Visible"/>
154: <Setter TargetName="RadioOuter" Property="BorderBrush" Value="#FFADADAD" />
155:
156: </Trigger>
157:
158: </ControlTemplate.Triggers>
159: </ControlTemplate>
160: </Setter.Value>
161: </Setter>
162: </Style>
163:
164: </ResourceDictionary>
2. Встановлення стилів для UI елементів через ссилку Dynamic Resource .
<TabItem Name="TabDR" Header="Skinning using Dynamic Resource"><Grid Grid.Column="1"><Border Style="{DynamicResource BorderStyle}" ><Grid><Grid.RowDefinitions><RowDefinition></RowDefinition><RowDefinition></RowDefinition><RowDefinition></RowDefinition><RowDefinition></RowDefinition><RowDefinition></RowDefinition><RowDefinition></RowDefinition></Grid.RowDefinitions><Border Grid.Row="0"><Grid><Grid.ColumnDefinitions><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition></Grid.ColumnDefinitions><Label Grid.Column="0" Content="UserId" Style="{DynamicResource LabelStyle}" /><TextBox Grid.Column="1" Style="{DynamicResource TextBoxStyle}"/></Grid></Border><Border Grid.Row="1"><Grid><Grid.ColumnDefinitions><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition></Grid.ColumnDefinitions><Label Grid.Column="0" Content="Password" Style="{DynamicResource LabelStyle}"/><PasswordBox Grid.Column="1" Style="{DynamicResource PasswordBoxStyle}"></PasswordBox></Grid></Border><Border Grid.Row="2"><Grid><Grid.ColumnDefinitions><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition></Grid.ColumnDefinitions><Label Grid.Column="0" Content="Email" Style="{DynamicResource LabelStyle}"/><TextBox Grid.Column="1" Style="{DynamicResource TextBoxStyle}" /></Grid></Border><Border Grid.Row="3"><Grid><Grid.ColumnDefinitions><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition></Grid.ColumnDefinitions><Label Grid.Column="0" Content="First Name" Style="{DynamicResource LabelStyle}"/><TextBox Grid.Column="1" Style="{DynamicResource TextBoxStyle}" /></Grid></Border><Border Grid.Row="4"><Grid><Grid.ColumnDefinitions><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition></Grid.ColumnDefinitions><Label Grid.Column="0" Content="Last Name" Style="{DynamicResource LabelStyle}"/><TextBox Grid.Column="1" Style="{DynamicResource TextBoxStyle}" /></Grid></Border><Border Grid.Row="5"><Button Content="Submit" Grid.Row="4" Style="{DynamicResource ButtonStyle}" /></Border></Grid></Border></Grid></TabItem>
3. Аплаїння нового скіну шляхом загрузки певної ResourceDictionary
private void OnSkinChanged(object sender, RoutedEventArgs e){App currentApp = Application.Current as App;string name = (e.OriginalSource as RadioButton).Name;currentApp.Resources.Clear();if (name == "None") return;ResourceDictionary skin = Application.LoadComponent(new Uri("Skins/" + name + ".xaml", UriKind.Relative)) as ResourceDictionary;currentApp.Resources.MergedDictionaries.Add(skin);e.Handled = true;}
Використання готових скінів !!!!
Нещодавно я знайшов опенсорсний проект WPF Themes на CodePlex,
Даний проект містить готовий набір таких скінів
- Expression Dark (From Silverlight Toolkit)
- Expression Light (From Silverlight Toolkit)
- Rainier Purple (From Silverlight Toolkit)
- Rainier Orange (From Silverlight Toolkit)
- Rainier Radial Blue
- Shiny Dark Green
- Shiny Dark Teal
- Shiny Dark Purple
- Shiny Blue (From Silverlight Toolkit)
- Shiny Red (From Silverlight Toolkit)
- Bureau Black
- Bureau Blue
- Whistler Blue
- UX Musing Red (From CorrinaB)
- UX Musing Green (From CorrinaB)
- UX Musing Rough
- UX Musing Rough Green (From CorrinaB)
- UX Musing Rough Red (From CorrinaB)
- UX Musing Bubbly
- UX Musing Bubbly Blue (From CorrinaB)
Список контролів , які підтримують ці теми:
- Button
- ToggleButton
- RadioButton
- CheckBox
- TextBox
- ComboBox
- ListBox
- ProgressBar
- Slider
- TreeView
- Expander
- Planned
Скачати цей проект можна тут CodePlex
Детальнішу інформацію про WPF.Themes.dll можна прочитати тут http://jiezhu0815.blogspot.com/2011/10/apply-themes-to-net-40-wpf-applications.html
Theming
Theming - механізм, який дозволяє використовувати візуальні характеристики операційної системи, з можливістю змін налаштування юзером.
На приклад, зміна Windows теми на Windows Classic надає баттонам і скролбарам плоский вигляд. Або у Windows XP переключення
з дефолтної кольорової схеми на Blue, Olive Green, або Silver впливає на колір і вигляд стандартних контролів.
Також важливо зрозуміти як працює темінг при створені власних кастомних контролів для гармонізації з темою операційної системи
В даному пості наведу 2 приклади темінгу :
- 1 спосіб - проcтий, але не потужний
- 2 спосіб - трохи складніший, але більш гнучкіший
1 спосіб - використання System Colors, Fonts, і Parameters
- Клас SystemColors надає доступ до налаштувань кольору.
- Клас SystemFonts забезпечує доступ до налаштувань шрифтів.
- Клас SystemParameters охоплює величезний список налаштувань, які описують стандартний розмір різних екранних елементів, параметри клавіатури і миші, розмір екрану, а також активні графічні ефекти (на зразок відкидання тіней і відображення вмісту вікон при перетягуванні).
Проперті, які надаються класами SystemColors, SystemFonts , and SystemParameters автоматично апдейтаються , коли міняється Windows тема. Таким чином включення їх в Стилі і темплейти являється легким способом використовувати візуальні характеристики операційної системи.
<Style x:Key="ButtonStyle" TargetType="Button" >
<Style.Resources>
<LinearGradientBrush x:Key="foregroundBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="{DynamicResource {x:Static SystemColors.InactiveCaptionColorKey}}"/>
<GradientStop Offset="0.5" Color="{DynamicResource {x:Static SystemColors.InactiveCaptionColorKey}}"/>
<GradientStop Offset="1" Color="{DynamicResource {x:Static SystemColors.ActiveCaptionColorKey}}"/>
</LinearGradientBrush>
</Style.Resources>
<Setter Property="Foreground" Value="{StaticResource foregroundBrush}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Style>
2 спосіб – написання стилів і темплейтів для кожної Windows теми.
Багато вбудованих елементів WPF маю різний вигляд в залежності від оброної Windows теми Наприклад, вони зазвичай
блискучі в Windows 7 Aero і менш привабливі в Windows Classic. Це досягається за допомогою окремих шаблонів елемента для кожної теми.
2 спосіб теммінгу полягає в написанні власних стилів і темплейтів, логічно згрупованих в теми , і використання їх при зміні Windows теми.
Давайте розглянемо по кроках
Перший крок полягає в :
- розміщенні темо-повязаних ресурсів в різні resource dictionary (це і є наші теми).
- далі необхідно розмістити ці теми в папку Themes (ця папочка обовязково має бути в руті проекту).
- назвати теми - ThemeName.ThemeColor.xaml (Слід зауважити, що URI теми Windows Classic не має ThemeColor )
- вказати резервну тему Themes \ Generic.xaml, яка буде використовуватись, якщо не має теми, яка б відповідала поточній темі Windows.
Тема загружається і аплається автоматично при зміні Windows теми.
Нище наведено існуючі теми Windows :
- The Aero theme (Windows Vista and Windows 7): themes\Aero.NormalColor.xam
- The default Windows XP theme: themes\Luna.NormalColor.xaml
- The olive green Windows XP theme: themes\Luna.Homestead.xaml
- The silver Windows XP theme: themes\Luna.Metallic.xaml
- The Windows XP Media Center Edition 2005 and Windows XP Tablet PC Edition 2005 theme: themes\Royale.NormalColor.xaml
- The Windows Classic theme: themes\Classic.xaml
- The Zune Windows XP theme: themes\Zune.NormalColor.xaml
2. Другий крок – настройка ThemeInfo
Аттрибут ThemeInfo вказує де автоматичний механізм темінгу повинен шукати тему і generic dictionary.
Можна проставити наступні значення:
- None (default): – не шукає resource dictionary.
- SourceAssembly: Resource dictionary знаходиться в поточній ассемблі.
- ExternalAssembly: Resource dictionary знаходиться в іншій ассемблі, яка названа
<AssemblyName>.<ThemeName>.dll, де<AssemblyName>назва ассемблі.
[assembly: ThemeInfo(
ResourceDictionaryLocation.SourceAssembly, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
В зааатаченом прикладі показано використання темінгу , в т.ч. для кастомного контролу MyCustomButton
Скачати приклад
Ну що ж, почитав я трохи про те чому застосуввання динамічних ресурсів пришвидшує завантаження аплікації, діло в тому, що ці ресурси підвантажуються при необхідності а статичні грузяться одразу всі при старті аплікухи.
ОтветитьУдалить