WPF之换肤

设计原理

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

截图

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

资源字典

规则样式资源Skin.RegularStyle.xaml

 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <!--Window样式-->
<Style x:Key="WindowStyle" TargetType="Window">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Window">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="Green" Offset="0"></GradientStop>
<GradientStop Color="LightGreen" Offset="0.4"></GradientStop>
<GradientStop Color="White" Offset="1"></GradientStop>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--Button样式-->
<Style TargetType="Button">
<Setter Property="Width" Value="70"></Setter>
<Setter Property="Height" Value="23"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="bdr" Cursor="Arrow"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="White" Offset="0"></GradientStop>
<GradientStop Color="LightGreen" Offset="0.3"></GradientStop>
<GradientStop Color="Green" Offset="1"></GradientStop>
</LinearGradientBrush>
</Border.Background>
<TextBlock Name="tbk" Background="Transparent" Foreground="DarkGreen" TextAlignment="Center"
Text="{TemplateBinding Content}"></TextBlock>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bdr" Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="LightGreen" Offset="0"></GradientStop>
<GradientStop Color="Green" Offset="1"></GradientStop>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="tbk" Property="Foreground" Value="White"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--TextBox样式-->
<Style TargetType="TextBox">
<Setter Property="FontFamily" Value="SketchFlow Print"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border BorderBrush="DarkGreen" BorderThickness="0.5">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"></ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--ContextMenu样式-->
<Style TargetType="ContextMenu">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu">
<Border BorderBrush="Green" BorderThickness="1">
<ItemsPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--MenuItem样式-->
<Style TargetType="MenuItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MenuItem">
<Border Name="border" Background="LightGreen" BorderThickness="0">
<TextBlock Name="tbk" Background="Transparent" Padding="5,5"
Text="{TemplateBinding Header}"></TextBlock>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="Green"></Setter>
<Setter TargetName="tbk" Property="Foreground" Value="White"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--TextBlock样式-->
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="SketchFlow Print"/>
<Setter Property="FontSize" Value="14"/>
</Style> </ResourceDictionary>

不规则样式资源Skin.RoundedCornerStyle.xaml

 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <!--Window样式-->
<Style x:Key="WindowStyle" TargetType="Window">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Window">
<Grid Margin="10">
<Rectangle Fill="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
RadiusX="5" RadiusY="5">
<Rectangle.Effect>
<DropShadowEffect BlurRadius="10" Color="Black" Direction="0" Opacity="0.8"
RenderingBias="Performance" ShadowDepth="0"/>
</Rectangle.Effect>
</Rectangle>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True" CornerRadius="5">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="Blue" Offset="0"></GradientStop>
<GradientStop Color="LightBlue" Offset="0.4"></GradientStop>
<GradientStop Color="White" Offset="1"></GradientStop>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter></ContentPresenter>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--Button样式-->
<Style TargetType="Button">
<Setter Property="Width" Value="70"></Setter>
<Setter Property="Height" Value="23"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="bdr" CornerRadius="5" Cursor="Hand"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBlock Name="tbk" Background="Transparent" Foreground="Yellow" TextAlignment="Center"
Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Content}"></TextBlock>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="White" Offset="0"></GradientStop>
<GradientStop Color="LightBlue" Offset="0.3"></GradientStop>
<GradientStop Color="Blue" Offset="1"></GradientStop>
</LinearGradientBrush>
</Border.Background>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bdr" Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="LightBlue" Offset="0"></GradientStop>
<GradientStop Color="Blue" Offset="1"></GradientStop>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="tbk" Property="Foreground" Value="LightYellow"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--TextBox样式-->
<Style TargetType="TextBox">
<Setter Property="FontFamily" Value="Times New Roman"></Setter>
<Setter Property="FontSize" Value="14"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border BorderBrush="Blue" BorderThickness="0.5" CornerRadius="5">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"></ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--ContextMenu样式-->
<Style TargetType="ContextMenu">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu">
<Border CornerRadius="5" BorderBrush="Blue" BorderThickness="1">
<ItemsPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--MenuItem样式-->
<Style TargetType="MenuItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MenuItem">
<Border Name="border" Background="LightSkyBlue" BorderThickness="0" CornerRadius="5">
<TextBlock Name="tbk" Background="Transparent" Padding="5,5"
Text="{TemplateBinding Header}"></TextBlock>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="BlueViolet"></Setter>
<Setter TargetName="tbk" Property="Foreground" Value="White"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <!--TextBlock样式-->
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Times New Roman"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</ResourceDictionary>

  仔细观察上面定义的样式,你会发现在定义Window样式的时候指定了Key,其他的Control样式却没有指定Key。大家都知道,如果没有给Style指定Key,那么这个Style会应用到所有目标类型(TargetType)为指定类型的Control。请看下面一段文字:

因为在换肤的过程中,需要动态加载Window的样式,所以用DynamicResource作绑定Style="{DynamicResource WindowStyle}"。

App.xaml

程序运行的时候,默认加载规则样式的皮肤。

     <Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary\Skin.RegularStyle.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

后台代码

         /// <summary>
/// MenuItem的执行方法
/// </summary>
/// <param name="parameter"></param>
private void RelayMenuItemEvent(object parameter)
{
if (parameter.ToString() == RegularStyle)
{
ChangeSkinResource(Skins[]);
}
else if (parameter.ToString() == RoundedCornerStyle)
{
ChangeSkinResource(Skins[]);
}
} /// <summary>
/// 更换皮肤资源
/// </summary>
/// <param name="skin"></param>
private void ChangeSkinResource(ResourceDictionary skin)
{
if (Application.Current.Resources.MergedDictionaries[].Source.IsAbsoluteUri)
{
if (Application.Current.Resources.MergedDictionaries[].Source.OriginalString != skin.Source.OriginalString)
{
Application.Current.Resources.MergedDictionaries[] = skin;
}
}
else
{
if (Application.Current.Resources.MergedDictionaries[].Source.OriginalString.ToString('\\') != skin.Source.OriginalString.ToString('/'))
{
Application.Current.Resources.MergedDictionaries[] = skin;
}
}
}

运行的时候在MainWindow上右键选择皮肤样式,就可以换肤了。

源码下载

链接

stackoverflow

WPF之换肤的更多相关文章

  1. WPF 实现换肤功能

    将所有控件的基本样式汇集到一个资源字典中,构成界面的基本样式文件,然后进行不同颜色皮肤的定制. 即在新的皮肤资源字典文件中引入基本样式文件,然后使用资源继承,并且只设置控件的颜色属性等,形成一个皮肤文 ...

  2. WPF style 换肤

    原文地址:http://www.cnblogs.com/DebugLZQ/p/3181040.html 原作者:DebugLZQ UI的风格一致性是应用程序应当关注的重要特性. 1.Creating ...

  3. 有点激动,WPF换肤搞定了!

    一如既往没废话! wpf桌面应用开发都是window内引入很多个UserControl. 如果你有通过不同颜色来换肤的需求,那么下面我就将整个过程! 分2个步骤: 1.主窗体背景色替换: 2.同时界面 ...

  4. WPF中使用DynamicResource实现换肤

    这篇将介绍使用DynamicResource实现动态的界面切换功能.熟悉WPF的园友应该已经猜到了实现方式,简而言之就是动态替换DataTemplate,ControlTemplate,Style等等 ...

  5. WPF换肤之八:创建3D浏览效果

    原文:WPF换肤之八:创建3D浏览效果 上节中,我们展示了WPF中的异步以及界面线程交互的方式,使得应用程序的显示更加的流畅.这节我们主要讲解如何设计一个具有3D浏览效果的天气信息浏览器. 效果显示 ...

  6. WPF换肤之六:酷炫的时区浏览小精灵

    原文:WPF换肤之六:酷炫的时区浏览小精灵 由于工作需要,经常要查看到不同地区的 当前时间,以前总是对照着时区表来进行加减运算,现在有了这个小工具以后,感觉省心了不少.下面是软件的截图: 效果图赏析 ...

  7. WPF换肤之七:异步

    原文:WPF换肤之七:异步 在WinForm时代,相信大家都遇到过这种情形,如果在程序设计过程中遇到了耗时的操作,不使用异步会导致程序假死.当然,在WPF中,这种情况也是存在的,所以我们就需要寻找一种 ...

  8. WPF换肤之四:界面设计和代码设计分离

    原文:WPF换肤之四:界面设计和代码设计分离 说起WPF来,除了总所周知的图形处理核心的变化外,和Winform比起来,还有一个巨大的变革,那就是真正意义上做到了界面设计和代码设计的分离.这样可以让美 ...

  9. WPF换肤之五:创建漂亮的窗体

    原文:WPF换肤之五:创建漂亮的窗体 换肤效果 经过了前面四章的讲解,我们终于知道了如何拖拉窗体使之改变大小,也知道了如何处理鼠标事件,同时,也知道了如何利用更好的编写方式来编写一个方便实用和维护的换 ...

随机推荐

  1. bzoj4815[CQOI2017]小Q的格子

    题意 不简述题意了,简述题意之后这道题就做出来了.放个原题面. 小Q是个程序员. 作为一个年轻的程序员,小Q总是被老C欺负,老C经常把一些麻烦的任务交给小Q来处理. 每当小Q不知道如何解决时,就只好向 ...

  2. vdbench测试过程中遇到的小问题

    1.报Slave hd2-0 prematurely terminated 错误 首先根据提示查看hd2-0.stdout.html文件获取更多的错误信息,这个问题一般是未安装vdbench或者路径不 ...

  3. byte数组转float实现与byte转换其它类型时进行&运算原理

    下面是将byte数组转换为float的实现 public static float getFloat(byte[] b) { int accum = 0; accum = accum|(b[0] &a ...

  4. Unity3D实现3D立体游戏原理及过程

    Unity3D实现3D立体游戏原理及过程 183 0 0     下面的教程是我今天整理的资料,教大家一步步完成自己的3D立体游戏,并向大家介绍一些3D成像的原理.     理论上,每个普通的非立体3 ...

  5. bzoj3306: 树(dfs序+倍增+线段树)

    比较傻逼的一道题... 显然求子树最小值就是求出dfs序用线段树维护嘛 换根的时候树的形态不会改变,所以我们可以根据相对于根的位置分类讨论. 如果询问的x是根就直接输出整棵树的最小值. 如果询问的x是 ...

  6. 【poj2068】Nim

    Portal -->poj2068 Description ​  给你\(S\)个石子,有\(2n\)个人分成两队,编号为奇数的一队,编号为偶数的一队,\(2n\)个人按照编号从小到大的顺序拿石 ...

  7. Java Web 生成临时文件并下载

    转自: Java Web 生成临时文件并下载 概述:本文是  java 服务器端生成文件并下载的示例,并不完善,下载之后一般来说还需要删除临时文件. 注意:临时文件存放在 /WEB-INF/tmp 目 ...

  8. Codeforces 895.C Square Subsets

    C. Square Subsets time limit per test 4 seconds memory limit per test 256 megabytes input standard i ...

  9. jbpm3.2创建数据库

    因为jbpm3.2的sql脚本有问题,所以我们通过查询来执行是有问题的,所以这里我们通过java代码来执行,这个是没有问题的. 参考博文: http://blog.csdn.net/sz_bdqn/a ...

  10. 「Python」pandas入门教程

    pandas适合于许多不同类型的数据,包括: 具有异构类型列的表格数据,例如SQL表格或Excel数据 有序和无序(不一定是固定频率)时间序列数据. 具有行列标签的任意矩阵数据(均匀类型或不同类型) ...