WPF之换肤
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上右键选择皮肤样式,就可以换肤了。
源码下载
链接
WPF之换肤的更多相关文章
- WPF 实现换肤功能
将所有控件的基本样式汇集到一个资源字典中,构成界面的基本样式文件,然后进行不同颜色皮肤的定制. 即在新的皮肤资源字典文件中引入基本样式文件,然后使用资源继承,并且只设置控件的颜色属性等,形成一个皮肤文 ...
- WPF style 换肤
原文地址:http://www.cnblogs.com/DebugLZQ/p/3181040.html 原作者:DebugLZQ UI的风格一致性是应用程序应当关注的重要特性. 1.Creating ...
- 有点激动,WPF换肤搞定了!
一如既往没废话! wpf桌面应用开发都是window内引入很多个UserControl. 如果你有通过不同颜色来换肤的需求,那么下面我就将整个过程! 分2个步骤: 1.主窗体背景色替换: 2.同时界面 ...
- WPF中使用DynamicResource实现换肤
这篇将介绍使用DynamicResource实现动态的界面切换功能.熟悉WPF的园友应该已经猜到了实现方式,简而言之就是动态替换DataTemplate,ControlTemplate,Style等等 ...
- WPF换肤之八:创建3D浏览效果
原文:WPF换肤之八:创建3D浏览效果 上节中,我们展示了WPF中的异步以及界面线程交互的方式,使得应用程序的显示更加的流畅.这节我们主要讲解如何设计一个具有3D浏览效果的天气信息浏览器. 效果显示 ...
- WPF换肤之六:酷炫的时区浏览小精灵
原文:WPF换肤之六:酷炫的时区浏览小精灵 由于工作需要,经常要查看到不同地区的 当前时间,以前总是对照着时区表来进行加减运算,现在有了这个小工具以后,感觉省心了不少.下面是软件的截图: 效果图赏析 ...
- WPF换肤之七:异步
原文:WPF换肤之七:异步 在WinForm时代,相信大家都遇到过这种情形,如果在程序设计过程中遇到了耗时的操作,不使用异步会导致程序假死.当然,在WPF中,这种情况也是存在的,所以我们就需要寻找一种 ...
- WPF换肤之四:界面设计和代码设计分离
原文:WPF换肤之四:界面设计和代码设计分离 说起WPF来,除了总所周知的图形处理核心的变化外,和Winform比起来,还有一个巨大的变革,那就是真正意义上做到了界面设计和代码设计的分离.这样可以让美 ...
- WPF换肤之五:创建漂亮的窗体
原文:WPF换肤之五:创建漂亮的窗体 换肤效果 经过了前面四章的讲解,我们终于知道了如何拖拉窗体使之改变大小,也知道了如何处理鼠标事件,同时,也知道了如何利用更好的编写方式来编写一个方便实用和维护的换 ...
随机推荐
- 【JavaScript】20款漂亮的css字体
样式一: body { margin: 0; padding: 0; line-height: 1.5em; font-family: "Times New Roman", Tim ...
- Qt浅谈内存泄露(总结)
Qt浅谈内存泄露(总结) 来源 http://blog.csdn.net/taiyang1987912/article/details/29271549 一.简介 Qt内存管理机制:Qt 在内部能够维 ...
- 【BZOJ2138】stone(线段树,Hall定理)
[BZOJ2138]stone(线段树,Hall定理) 题面 BZOJ 题解 考虑一个暴力. 我们对于每堆石子和每个询问,显然是匹配的操作. 所以可以把石子拆成\(a_i\)个,询问点拆成\(K_i\ ...
- 洛谷U14667 肝活动【比赛】 【状压dp】
题目描述 Yume 最近在玩一个名为<LoveLive! School idol festival>的音乐游戏.他之所以喜欢上这个游戏,是因为这个游戏对非洲人十分友好,即便你脸黑到抽不出好 ...
- 洛谷 P4066 [SHOI2003]吃豆豆 解题报告
P4066 [SHOI2003]吃豆豆 题目描述 两个PACMAN吃豆豆.一开始的时候,PACMAN都在坐标原点的左下方,豆豆都在右上方.PACMAN走到豆豆处就会吃掉它.PACMAN行走的路线很奇怪 ...
- HDU.1166 敌兵布阵 (线段树 单点更新 区间查询)
HDU.1166 敌兵布阵 (线段树 单点更新 区间查询) 题意分析 加深理解,重写一遍 代码总览 #include <bits/stdc++.h> #define nmax 100000 ...
- HDU.1394 Minimum Inversion Number (线段树 单点更新 区间求和 逆序对)
HDU.1394 Minimum Inversion Number (线段树 单点更新 区间求和 逆序对) 题意分析 给出n个数的序列,a1,a2,a3--an,ai∈[0,n-1],求环序列中逆序对 ...
- 解题:BOI 2008 Elect
题面 做背包时可以通过排序来使得转移满足某种限制或是让我们判断一个状态是否有贡献 这个题将人数从大到小排序后做背包,这样每次那个最小的党加入而使得答案合法时之前的党也都是合法的 #include< ...
- 【CF601C】Kleofáš and the n-thlon
Portal -->CF601C Description 大概是说\(m\)个人参加\(n\)场比赛,每场一人有一个排名,每场没有两个人排名相同,一个人最后的得分是\(n\)场比赛的排名相加,现 ...
- Python3 字典 clear()方法
Python3 字典 描述 Python 字典 clear() 函数用于删除字典内所有元素. 语法 clear()方法语法: dict.clear() 参数 NA. 返回值 该函数没有任何返回值. ...