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. 51nod 1677 treecnt(思维)

    题意: 给定一棵n个节点的树,从1到n标号.选择k个点,你需要选择一些边使得这k个点通过选择的边联通,目标是使得选择的边数最少. 现需要计算对于所有选择k个点的情况最小选择边数的总和为多少. 考虑每条 ...

  2. BZOJ 1228 E&G(sg函数+找规律)

    把一对石子堆看出一个子游戏.打出子游戏的sg表找规律.. 这个规律我是一定找不出来的... 对于i,j,如果 (i-1)%pow(2,k+1) < pow(2,k) (j-1)%pow(2,k+ ...

  3. Tajo--一个分布式数据仓库系统(设计架构)

    上一篇Tajo--一个分布式数据仓库系统(概述)废话了一通,下面介绍一下Tajo的体系结构.以及官方的实验成果吧 一.体系架构 Tajo采用了Master-Worker架构(下图虚线框目前还在计划中) ...

  4. 洛谷 U14472 数据结构【比赛】 【差分数组 + 前缀和】

    题目描述 蒟蒻Edt把这个问题交给了你 ---- 一个精通数据结构的大犇,由于是第一题,这个题没那么难.. edt 现在对于题目进行了如下的简化: 最开始的数组每个元素都是0 给出nnn,optopt ...

  5. 【原创】【2】rich editor系列教程。了解document.execommand操作,保存丢失的range,实时反馈样式给工具栏

    [原创][2]rich editor系列教程.了解document.execommand操作,保存丢失的range,实时反馈样式给工具栏 索引目录:http://www.cnblogs.com/hen ...

  6. javascript中的位运算,

    罗浮宫群里又有讨论位运算符号|了,做过一段时间php,数据库保存布尔值数据经常用到,比如100110 就表明了六个属性的是与否,极大减少了数据量..] ECMAScript 中位运算跟其他语言一样的. ...

  7. [POI2005]Bank notes

    link 试题分析 我们发现此题是一个十分简单的多重背包.但是按照朴素写法会超时.所以要去考虑优化. 我们发现我们若$W=7$,可以拆成$1+2+4$,不用每次$1+1+1+1+1+1+1$,从$N$ ...

  8. 【loj2133】【NOI2015】品酒大会

    Portal --> loj2133 Solution 虽然说这题貌似用后缀树之类的好像会更加简短一点..但是还是因为在智力康复所以就还是用后缀数组好了嗯(哇好感动啊难得那么顺畅写了一道noi的 ...

  9. Qt ------ QTabWidget

    下图: 1.长方形的 objectName 可写可不写,不写就作用于所有 QTabWidget:椭圆形的 QTabWidget#tabWidget 要么四个都要写,要么四个都不写 2.下图的 CSS ...

  10. Bootstrapping算法

    sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频) https://study.163.com/course/introduction.htm?courseId=1005269003& ...