WPF换肤设计原理浅析
作者:sunny906 发布时间:2022-11-18 00:37:00
标签: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[0]);
}
else if (parameter.ToString() == RoundedCornerStyle)
{
ChangeSkinResource(Skins[1]);
}
}
/// <summary>
/// 更换皮肤资源
/// </summary>
/// <param name="skin"></param>
private void ChangeSkinResource(ResourceDictionary skin)
{
if (Application.Current.Resources.MergedDictionaries[0].Source.IsAbsoluteUri)
{
if (Application.Current.Resources.MergedDictionaries[0].Source.OriginalString != skin.Source.OriginalString)
{
Application.Current.Resources.MergedDictionaries[0] = skin;
}
}
else
{
if (Application.Current.Resources.MergedDictionaries[0].Source.OriginalString.ToString('\\') != skin.Source.OriginalString.ToString('/'))
{
Application.Current.Resources.MergedDictionaries[0] = skin;
}
}
}
运行的时候在MainWindow上右键选择皮肤样式,就可以换肤了。
源码下载:http://xiazai.jb51.net/201610/yuanma/WPFSkin(jb51.net).rar
链接:stackoverflow
0
投稿
猜你喜欢
- Activities提供了一种方便管理的创建、保存、回复的对话框机制,例如 onCreateDialog(int), onPrepareDi
- 1.需求WPF本身没有直接把点集合绘制成曲线的函数。可以通过贝塞尔曲线函数来绘制。贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩
- 前言在阅读本文之前, 希望你可以思考一下下面几个问题, 带着问题去阅读文章会获得更好的效果。发送消息的时候, 当Broker挂掉了,消息体还
- 前言上一篇文章中我们通过自己开发了一个负载均衡组件,实现了随机算法的负载均衡功能,如果要实现其他算法,还需要修改代码增加相应的功能。这一篇文
- Gradle 属性( Gradle build environment)[详细信息]("https://docs.gradle.o
- 在Java中进行日期处理大家一定都不陌生,我们经常会需要在代码中进行日期的转换、日期的格式化等操作。而一般我们进行日期格式化的时候都会使用S
- WebView是Android中一个非常实用的组件,它和Safai、Chrome一样都是基于Webkit网页渲染引擎,可以通过加载HTML数
- 服务器端代码:import java.io.BufferedReader; import java.io.InputStreamR
- 定义工具类-创建对应的日志对象定义枚举类-存储定义的日志文件名称logback.xml里配置对应的日志名称和日志等级1、工具类 Logger
- 基本思路服务器配置如下:192.168.159.50 gitlab服务器(Gitlab,内存至少5个G,要不根本跑不动)192.168.15
- 1.循环遍历private void GetControls(Control fatherControl){ Co
- 一、synchronized 有不足新事物的出现要不是替代老事物,要么就是对老事物的补充JUC 的 locks 就是对 synchroniz
- 将某个项目从Spring Boot1升级Spring Boot2之后出现如下报错,查了很多不同的解决方法都没有解决:Spring boot2
- C# 和 java 比较:java 中使用的是接口。C# 使用委托机制,可以用时 + 运算符进行注册,直接多播。而 java 中是一般是使用
- 这里之所以说“浅谈”是因为我这里只是简单的介绍如何使用Visual C#进行图像的读入、保存以及对像素的访问。而不涉及太多的算法。一、读取图
- 我们在做微服务时,有时候需要将微服务做一些限制,比如只能我们自己的服务调用,不能通过浏览器直接调用等。我们可以使用spring cloud
- Android Handler的使用,在讲Handler之前,我们先提个小问题,就是如何让程序5秒钟更新一下Title.首先我们看一下习惯了
- Android 处理OnItemClickListener时关于焦点颜色的设置问题  
- 本文实例讲述了C#使用文件流读取文件的方法。分享给大家供大家参考。具体如下:using System;using System.IO;nam
- 线程的作用和意义线程 被定义为程序的执行路径。每个线程都定义了一个独特的控制流。如果您的应用程序涉及到复杂的和耗时的操作,那么设置不同的线程