wpf 换肤 的设计原理,利用资源字典为每种皮肤资源添加不同的样式,在后台切换皮肤资源文件。
截图
上图中,第一张图采用规则样式,第二张图采用不规则样式,截图的时候略有瑕疵。
资源字典
规则样式资源skin.regularstyle.xaml
< resourcedictionary xmlns = "http://schemas.microsoft测试数据/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft测试数据/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测试数据/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft测试数据/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上右键选择皮肤样式,就可以换肤了。
源码下载: wpfskin.rar
链接: stackoverflow
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
dy("nrwz");