WPF之换肤
设计原理
WPF换肤的设计原理,利用资源字典为每种皮肤资源添加不同的样式,在后台切换皮肤资源文件。
截图
上图中,第一张图采用规则样式,第二张图采用不规则样式,截图的时候略有瑕疵。
资源字典
规则样式资源Skin.RegularStyle.xaml
1 <ResourceDictionary ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 2 ="http://schemas.microsoft.com/winfx/2006/xaml"> 3 4 <!--Window样式--> 5 <Style x:Key="WindowStyle" TargetType="Window"> 6 <Setter Property="Template"> 7 <Setter.Value> 8 <ControlTemplate TargetType="Window"> 9 <Border BorderBrush="{TemplateBinding BorderBrush}" 10 BorderThickness="{TemplateBinding BorderThickness}"> 11 <Border.Background> 12 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> 13 <GradientStop Color="Green" Offset="0"></GradientStop> 14 <GradientStop Color="LightGreen" Offset="0.4"></GradientStop> 15 <GradientStop Color="White" Offset="1"></GradientStop> 16 </LinearGradientBrush> 17 </Border.Background> 18 <ContentPresenter></ContentPresenter> 19 </Border> 20 </ControlTemplate> 21 </Setter.Value> 22 </Setter> 23 </Style> 24 25 <!--Button样式--> 26 <Style TargetType="Button"> 27 <Setter Property="Width" Value="70"></Setter> 28 <Setter Property="Height" Value="23"></Setter> 29 <Setter Property="Template"> 30 <Setter.Value> 31 <ControlTemplate TargetType="Button"> 32 <Border Name="bdr" Cursor="Arrow" 33 BorderBrush="{TemplateBinding BorderBrush}" 34 BorderThickness="{TemplateBinding BorderThickness}"> 35 <Border.Background> 36 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> 37 <GradientStop Color="White" Offset="0"></GradientStop> 38 <GradientStop Color="LightGreen" Offset="0.3"></GradientStop> 39 <GradientStop Color="Green" Offset="1"></GradientStop> 40 </LinearGradientBrush> 41 </Border.Background> 42 <TextBlock Name="tbk" Background="Transparent" Foreground="DarkGreen" TextAlignment="Center" 43 Text="{TemplateBinding Content}"></TextBlock> 44 </Border> 45 <ControlTemplate.Triggers> 46 <Trigger Property="IsMouseOver" Value="True"> 47 <Setter TargetName="bdr" Property="Background"> 48 <Setter.Value> 49 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> 50 <GradientStop Color="LightGreen" Offset="0"></GradientStop> 51 <GradientStop Color="Green" Offset="1"></GradientStop> 52 </LinearGradientBrush> 53 </Setter.Value> 54 </Setter> 55 <Setter TargetName="tbk" Property="Foreground" Value="White"></Setter> 56 </Trigger> 57 </ControlTemplate.Triggers> 58 </ControlTemplate> 59 </Setter.Value> 60 </Setter> 61 </Style> 62 63 <!--TextBox样式--> 64 <Style TargetType="TextBox"> 65 <Setter Property="FontFamily" Value="SketchFlow Print"/> 66 <Setter Property="FontSize" Value="14"/> 67 <Setter Property="Template"> 68 <Setter.Value> 69 <ControlTemplate TargetType="TextBox"> 70 <Border BorderBrush="DarkGreen" BorderThickness="0.5"> 71 <ScrollViewer x:Name="PART_ContentHost" Focusable="false" 72 HorizontalScrollBarVisibility="Hidden" 73 VerticalScrollBarVisibility="Hidden"></ScrollViewer> 74 </Border> 75 </ControlTemplate> 76 </Setter.Value> 77 </Setter> 78 </Style> 79 80 <!--ContextMenu样式--> 81 <Style TargetType="ContextMenu"> 82 <Setter Property="Template"> 83 <Setter.Value> 84 <ControlTemplate TargetType="ContextMenu"> 85 <Border BorderBrush="Green" BorderThickness="1"> 86 <ItemsPresenter/> 87 </Border> 88 </ControlTemplate> 89 </Setter.Value> 90 </Setter> 91 </Style> 92 93 <!--MenuItem样式--> 94 <Style TargetType="MenuItem"> 95 <Setter Property="Template"> 96 <Setter.Value> 97 <ControlTemplate TargetType="MenuItem"> 98 <Border Name="border" Background="LightGreen" BorderThickness="0"> 99 <TextBlock Name="tbk" Background="Transparent" Padding="5,5"100 Text="{TemplateBinding Header}"></TextBlock>101 </Border>102 <ControlTemplate.Triggers>103 <Trigger Property="IsMouseOver" Value="True">104 <Setter TargetName="border" Property="Background" Value="Green"></Setter>105 <Setter TargetName="tbk" Property="Foreground" Value="White"></Setter>106 </Trigger>107 </ControlTemplate.Triggers>108 </ControlTemplate>109 </Setter.Value>110 </Setter>111 </Style>112 113 <!--TextBlock样式-->114 <Style TargetType="TextBlock">115 <Setter Property="FontFamily" Value="SketchFlow Print"/>116 <Setter Property="FontSize" Value="14"/>117 </Style>118 119 </ResourceDictionary>
View Code
不规则样式资源Skin.RoundedCornerStyle.xaml
1 <ResourceDictionary ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 2 ="http://schemas.microsoft.com/winfx/2006/xaml"> 3 4 <!--Window样式--> 5 <Style x:Key="WindowStyle" TargetType="Window"> 6 <Setter Property="Template"> 7 <Setter.Value> 8 <ControlTemplate TargetType="Window"> 9 <Grid Margin="10"> 10 <Rectangle Fill="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" 11 RadiusX="5" RadiusY="5"> 12 <Rectangle.Effect> 13 <DropShadowEffect BlurRadius="10" Color="Black" Direction="0" Opacity="0.8" 14 RenderingBias="Performance" ShadowDepth="0"/> 15 </Rectangle.Effect> 16 </Rectangle> 17 <Border BorderBrush="{TemplateBinding BorderBrush}" 18 BorderThickness="{TemplateBinding BorderThickness}" 19 SnapsToDevicePixels="True" CornerRadius="5"> 20 <Border.Background> 21 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> 22 <GradientStop Color="Blue" Offset="0"></GradientStop> 23 <GradientStop Color="LightBlue" Offset="0.4"></GradientStop> 24 <GradientStop Color="White" Offset="1"></GradientStop> 25 </LinearGradientBrush> 26 </Border.Background> 27 <ContentPresenter></ContentPresenter> 28 </Border> 29 </Grid> 30 </ControlTemplate> 31 </Setter.Value> 32 </Setter> 33 </Style> 34 35 <!--Button样式--> 36 <Style TargetType="Button"> 37 <Setter Property="Width" Value="70"></Setter> 38 <Setter Property="Height" Value="23"></Setter> 39 <Setter Property="Template"> 40 <Setter.Value> 41 <ControlTemplate TargetType="Button"> 42 <Border Name="bdr" CornerRadius="5" Cursor="Hand" 43 BorderBrush="{TemplateBinding BorderBrush}" 44 BorderThickness="{TemplateBinding BorderThickness}"> 45 <TextBlock Name="tbk" Background="Transparent" Foreground="Yellow" TextAlignment="Center" 46 Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Content}"></TextBlock> 47 <Border.Background> 48 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> 49 <GradientStop Color="White" Offset="0"></GradientStop> 50 <GradientStop Color="LightBlue" Offset="0.3"></GradientStop> 51 <GradientStop Color="Blue" Offset="1"></GradientStop> 52 </LinearGradientBrush> 53 </Border.Background> 54 </Border> 55 <ControlTemplate.Triggers> 56 <Trigger Property="IsMouseOver" Value="True"> 57 <Setter TargetName="bdr" Property="Background"> 58 <Setter.Value> 59 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> 60 <GradientStop Color="LightBlue" Offset="0"></GradientStop> 61 <GradientStop Color="Blue" Offset="1"></GradientStop> 62 </LinearGradientBrush> 63 </Setter.Value> 64 </Setter> 65 <Setter TargetName="tbk" Property="Foreground" Value="LightYellow"></Setter> 66 </Trigger> 67 </ControlTemplate.Triggers> 68 </ControlTemplate> 69 </Setter.Value> 70 </Setter> 71 </Style> 72 73 <!--TextBox样式--> 74 <Style TargetType="TextBox"> 75 <Setter Property="FontFamily" Value="Times New Roman"></Setter> 76 <Setter Property="FontSize" Value="14"></Setter> 77 <Setter Property="Template"> 78 <Setter.Value> 79 <ControlTemplate TargetType="TextBox"> 80 <Border BorderBrush="Blue" BorderThickness="0.5" CornerRadius="5"> 81 <ScrollViewer x:Name="PART_ContentHost" Focusable="false" 82 HorizontalScrollBarVisibility="Hidden" 83 VerticalScrollBarVisibility="Hidden"></ScrollViewer> 84 </Border> 85 </ControlTemplate> 86 </Setter.Value> 87 </Setter> 88 </Style> 89 90 <!--ContextMenu样式--> 91 <Style TargetType="ContextMenu"> 92 <Setter Property="Template"> 93 <Setter.Value> 94 <ControlTemplate TargetType="ContextMenu"> 95 <Border CornerRadius="5" BorderBrush="Blue" BorderThickness="1"> 96 <ItemsPresenter/> 97 </Border> 98 </ControlTemplate> 99 </Setter.Value>100 </Setter>101 </Style>102 103 <!--MenuItem样式-->104 <Style TargetType="MenuItem">105 <Setter Property="Template">106 <Setter.Value>107 <ControlTemplate TargetType="MenuItem">108 <Border Name="border" Background="LightSkyBlue" BorderThickness="0" CornerRadius="5">109 <TextBlock Name="tbk" Background="Transparent" Padding="5,5"110 Text="{TemplateBinding Header}"></TextBlock>111 </Border>112 <ControlTemplate.Triggers>113 <Trigger Property="IsMouseOver" Value="True">114 <Setter TargetName="border" Property="Background" Value="BlueViolet"></Setter>115 <Setter TargetName="tbk" Property="Foreground" Value="White"></Setter>116 </Trigger>117 </ControlTemplate.Triggers>118 </ControlTemplate>119 </Setter.Value>120 </Setter>121 </Style>122 123 <!--TextBlock样式-->124 <Style TargetType="TextBlock">125 <Setter Property="FontFamily" Value="Times New Roman"/>126 <Setter Property="FontSize" Value="14"/>127 </Style>128 </ResourceDictionary>
View Code
仔细观察上面定义的样式,你会发现在定义Window样式的时候指定了Key,其他的Control样式却没有指定Key。大家都知道,如果没有给Style指定Key,那么这个Style会应用到所有目标类型(TargetType)为指定类型的Control。请看下面一段文字:
因为在换肤的过程中,需要动态加载Window的样式,所以用DynamicResource作绑定。
App.xaml
程序运行的时候,默认加载规则样式的皮肤。
1 <Application.Resources>2 <ResourceDictionary>3 <ResourceDictionary.MergedDictionaries>4 <ResourceDictionary Source="Dictionary\Skin.RegularStyle.xaml"></ResourceDictionary>5 </ResourceDictionary.MergedDictionaries>6 </ResourceDictionary>7 </Application.Resources>
View Code
后台代码
1 /// <summary> 2 /// MenuItem的执行方法 3 /// </summary> 4 /// <param name="parameter"></param> 5 private void RelayMenuItemEvent(object parameter) 6 { 7 if (parameter.ToString() == RegularStyle) 8 { 9 ChangeSkinResource(Skins[0]);10 }11 else if (parameter.ToString() == RoundedCornerStyle)12 {13 ChangeSkinResource(Skins[1]);14 }15 }16 17 /// <summary>18 /// 更换皮肤资源19 /// </summary>20 /// <param name="skin"></param>21 private void ChangeSkinResource(ResourceDictionary skin)22 {23 if (Application.Current.Resources.MergedDictionaries[0].Source.IsAbsoluteUri)24 {25 if (Application.Current.Resources.MergedDictionaries[0].Source.OriginalString != skin.Source.OriginalString)26 {27 Application.Current.Resources.MergedDictionaries[0] = skin;28 }29 }30 else31 {32 if (Application.Current.Resources.MergedDictionaries[0].Source.OriginalString.ToString('\\') != skin.Source.OriginalString.ToString('/'))33 {34 Application.Current.Resources.MergedDictionaries[0] = skin;35 }36 }37 }
View Code
运行的时候在MainWindow上右键选择皮肤样式,就可以换肤了。
源码下载
链接
stackoverflow
原标题:WPF之换肤
关键词:wpf