首页 > 技术文章 > WPF之换肤

zhou-yi 2015-05-26 09:18 原文

WPF之换肤

设计原理

WPF换肤的设计原理,利用资源字典为每种皮肤资源添加不同的样式,在后台切换皮肤资源文件。

截图

上图中,第一张图采用规则样式,第二张图采用不规则样式,截图的时候略有瑕疵。

资源字典

规则样式资源Skin.RegularStyle.xaml

  1 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  2                     xmlns:x="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 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  2                     xmlns:x="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作绑定Style="{DynamicResource WindowStyle}"。

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             else
31             {
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

推荐阅读