WPF滑块控件(Slider)的自定义样式
前言
每次开发滑块控件的样式都要花很久去读样式代码,感觉有点记不牢,所以特此备忘。
自定义滑块样式
首先创建项目,添加slider控件。
然后获取slider的window样式,如下图操作。
然后弹出界面如下.我们点击确定。
点击确定后,我们的页面的resources中,增加了一系列样式代码,而滑块代码会被修改为如下样子:
<slider horizontalalignment="left" width="200" verticalalignment="top" style="{dynamicresource sliderstyle1}"/>
可以看到,系统为我们的slider控件增加了样式——style="{dynamicresource sliderstyle1}"
现在我们查看样式sliderstyle1,f12跟踪到定义。
<style x:key="sliderstyle1" targettype="{x:type slider}">
<setter property="stylus.ispressandholdenabled" value="false"/>
<setter property="background" value="transparent"/>
<setter property="borderbrush" value="transparent"/>
<setter property="foreground" value="{staticresource sliderthumb.static.foreground}"/>
<setter property="template" value="{staticresource sliderhorizontal}"/>
<style.triggers>
<trigger property="orientation" value="vertical">
<setter property="template" value="{staticresource slidervertical}"/>
</trigger>
</style.triggers>
</style>
上述代码中我们可以看发现slider使用的模板是sliderhorizontal,但当他的排列方向为vertical时,则使用slidervertical模板。
因为slider控件默认是横向布局,所以我们先修改sliderhorizontal模板,对slider进行下美化。
同样,我们继续f12跟进sliderhorizontal的定义。
<controltemplate x:key="sliderhorizontal" targettype="{x:type slider}">
<border x:name="border" borderbrush="{templatebinding borderbrush}" borderthickness="{templatebinding borderthickness}" background="{templatebinding background}" snapstodevicepixels="true">
<grid>
<grid.rowdefinitions>
<rowdefinition height="auto"/>
<rowdefinition height="auto" minheight="{templatebinding minheight}"/>
<rowdefinition height="auto"/>
</grid.rowdefinitions>
<tickbar x:name="toptick" fill="{templatebinding foreground}" height="4" margin="0,0,0,2" placement="top" grid.row="0" visibility="collapsed"/>
<tickbar x:name="bottomtick" fill="{templatebinding foreground}" height="4" margin="0,2,0,0" placement="bottom" grid.row="2" visibility="collapsed"/>
<border x:name="trackbackground" borderbrush="{staticresource sliderthumb.track.border}" borderthickness="1" background="{staticresource sliderthumb.track.background}" height="4.0" margin="5,0" grid.row="1" verticalalignment="center">
<canvas margin="-6,-1">
<rectangle x:name="part_selectionrange" fill="{dynamicresource {x:static systemcolors.highlightbrushkey}}" height="4.0" visibility="hidden"/>
</canvas>
</border>
<track x:name="part_track" grid.row="1">
<track.decreaserepeatbutton>
<repeatbutton command="{x:static slider.decreaselarge}" style="{staticresource repeatbuttontransparent}"/>
</track.decreaserepeatbutton>
<track.increaserepeatbutton>
<repeatbutton command="{x:static slider.increaselarge}" style="{staticresource repeatbuttontransparent}"/>
</track.increaserepeatbutton>
<track.thumb>
<thumb x:name="thumb" focusable="false" height="18" overridesdefaultstyle="true" template="{staticresource sliderthumbhorizontaldefault}" verticalalignment="center" width="11"/>
</track.thumb>
</track>
</grid>
</border>
<controltemplate.triggers>
<trigger property="tickplacement" value="topleft">
<setter property="visibility" targetname="toptick" value="visible"/>
<setter property="template" targetname="thumb" value="{staticresource sliderthumbhorizontaltop}"/>
<setter property="margin" targetname="trackbackground" value="5,2,5,0"/>
</trigger>
<trigger property="tickplacement" value="bottomright">
<setter property="visibility" targetname="bottomtick" value="visible"/>
<setter property="template" targetname="thumb" value="{staticresource sliderthumbhorizontalbottom}"/>
<setter property="margin" targetname="trackbackground" value="5,0,5,2"/>
</trigger>
<trigger property="tickplacement" value="both">
<setter property="visibility" targetname="toptick" value="visible"/>
<setter property="visibility" targetname="bottomtick" value="visible"/>
</trigger>
<trigger property="isselectionrangeenabled" value="true">
<setter property="visibility" targetname="part_selectionrange" value="visible"/>
</trigger>
<trigger property="iskeyboardfocused" value="true">
<setter property="foreground" targetname="thumb" value="blue"/>
</trigger>
</controltemplate.triggers>
</controltemplate>
sliderhorizontal模板的定义比较多,这里直接定义到重点内容——轨道。
首先定位到代码【border x:name="trackbackground"】,这里的trackbackground是控制滑块背景颜色的,我们修改其背景颜色和边框颜色。
<border x:name="trackbackground" borderbrush="red" borderthickness="1" background="yellow" height="4.0" margin="5,0" grid.row="1" verticalalignment="center">
<canvas margin="-6,-1">
<rectangle x:name="part_selectionrange" fill="{dynamicresource {x:static systemcolors.highlightbrushkey}}" height="4.0" visibility="hidden"/>
</canvas>
</border>
得到效果如下:
但我们有时候需要拖动前后颜色不一样,此时就靠背景修改就不够了。
在sliderhorizontal模板中找到decreaserepeatbutton和increaserepeatbutton;这两个一个是拖动前覆盖颜色,一个是拖动后覆盖颜色。
修改代码如下:
<track x:name="part_track" grid.row="1">
<track.decreaserepeatbutton>
<repeatbutton height="4" background="gray" command="{x:static slider.decreaselarge}" style="{staticresource repeatbuttontransparent}"/>
</track.decreaserepeatbutton>
<track.increaserepeatbutton>
<repeatbutton height="4" background="green" command="{x:static slider.increaselarge}" style="{staticresource repeatbuttontransparent}"/>
</track.increaserepeatbutton>
<track.thumb>
<thumb x:name="thumb" focusable="false" height="18" overridesdefaultstyle="true" template="{staticresource sliderthumbhorizontaldefault}" verticalalignment="center" width="11"/>
</track.thumb>
</track>
得到效果如下:
注意这里的height一定要给值。
现在,我们设置好了轨道,可当前的滑块的颜色我们有点不太满意,所以我们再来处理下滑块。
滑块模板的模板是上方代码中粉色标记的代码——thumb。
可以看到thumb使用的是sliderthumbhorizontaldefault模板,所以,我们继续f12跟进sliderthumbhorizontaldefault查看它的定义。
<controltemplate x:key="sliderthumbhorizontaldefault" targettype="{x:type thumb}">
<grid horizontalalignment="center" uselayoutrounding="true" verticalalignment="center">
<path x:name="grip" data="m 0,0 c0,0 11,0 11,0 11,0 11,18 11,18 11,18 0,18 0,18 0,18 0,0 0,0 z" fill="{staticresource sliderthumb.static.background}" stretch="fill" snapstodevicepixels="true" stroke="{staticresource sliderthumb.static.border}" strokethickness="1" uselayoutrounding="true" verticalalignment="center"/>
</grid>
<controltemplate.triggers>
<trigger property="ismouseover" value="true">
<setter property="fill" targetname="grip" value="{staticresource sliderthumb.mouseover.background}"/>
<setter property="stroke" targetname="grip" value="{staticresource sliderthumb.mouseover.border}"/>
</trigger>
<trigger property="isdragging" value="true">
<setter property="fill" targetname="grip" value="{staticresource sliderthumb.pressed.background}"/>
<setter property="stroke" targetname="grip" value="{staticresource sliderthumb.pressed.border}"/>
</trigger>
<trigger property="isenabled" value="false">
<setter property="fill" targetname="grip" value="{staticresource sliderthumb.disabled.background}"/>
<setter property="stroke" targetname="grip" value="{staticresource sliderthumb.disabled.border}"/>
</trigger>
</controltemplate.triggers>
</controltemplate>
从上述代码中可以看到,滑块定义很简单,布局就是一个grid里放了一个path,事件响应只有3个。
下面为修改path的fill填充色和stroke的划线颜色如下:
<path x:name="grip" data="m 0,0 c0,0 11,0 11,0 11,0 11,18 11,18 11,18 0,18 0,18 0,18 0,0 0,0 z" fill="red" stretch="fill" snapstodevicepixels="true" stroke="blue" strokethickness="1" uselayoutrounding="true" verticalalignment="center"/>
得到效果如下:
现在,我们觉得矩形的滑块不好看,需要用椭圆形的滑块,那么,我们再来处理下滑块。
首先删除thumb里定义的宽和高,因为不删除它们,模板里的宽高会受此限制。
删除后如下:
<track.thumb>
<thumb x:name="thumb" focusable="false" overridesdefaultstyle="true" template="{staticresource sliderthumbhorizontaldefault}" verticalalignment="center" />
</track.thumb>
现在我们再来修改sliderthumbhorizontaldefault模板。
在模板里找到path,修改他的data,之前他的data是自己画的一个矩形,现在我们给他改为椭圆形,并且给path重新设置宽高,如下:
<path x:name="grip" width="20" height="20" fill="red" stretch="fill" snapstodevicepixels="true" stroke="blue" strokethickness="1" uselayoutrounding="true" verticalalignment="center">
<path.data>
<ellipsegeometry center="10,10" radiusx="10" radiusy="10"></ellipsegeometry>
</path.data>
</path>
我们得到效果如下:
可以看到,图中的滑块是个圆形,而我们需要的是一个椭圆形。
处理很简单,修改path的width即可,我们该为14,得到效果如下:
当然,我们既然可以通过修改样式设计椭圆形滑块,就也可以设计其他形状滑块,比如,我们修改path如下,获得斜角四边形滑块:
<path x:name="grip" width="14" height="20" fill="red" stretch="fill" snapstodevicepixels="true" stroke="blue" strokethickness="1" uselayoutrounding="true" verticalalignment="center">
<path.data>
<pathgeometry>
<pathgeometry.figures>
<pathfigure startpoint="0,0" isclosed="true">
<linesegment point="0,0" />
<linesegment point="110,0" />
<linesegment point="70,40" />
<linesegment point="-40,40" />
</pathfigure>
</pathgeometry.figures>
</pathgeometry>
</path.data>
</path>
效果图如下:
修改代码如下,设置三角形滑块:
<path x:name="grip" width="14" height="20" fill="red" stretch="fill" snapstodevicepixels="true" stroke="blue" strokethickness="1" uselayoutrounding="true" verticalalignment="center">
<path.data>
<pathgeometry>
<pathgeometry.figures>
<pathfigure startpoint="0,0" isclosed="true">
<linesegment point="30,0" />
<linesegment point="15,100" />
</pathfigure>
</pathgeometry.figures>
</pathgeometry>
</path.data>
</path>
效果图如下:
----------------------------------------------------------------------------------------------------
上述代码设置的都是水平方向的滑块样式,垂直方向的滑块样式设置同理,只要从模板slidervertical开始,以此处理修改即可。
----------------------------------------------------------------------------------------------------
到此wpf滑块控件(slider)的自定义样式就已经讲解完成了。
代码已经传到github上了,欢迎大家下载。
github地址:https://github.com/kiba518/wpfslider
----------------------------------------------------------------------------------------------------
注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!
推荐阅读
-
如何在双向绑定的Image控件上绘制自定义标记(wpf)
-
[WPF自定义控件库]使用TextBlockHighlightSource强化高亮的功能,以及使用TypeConverter简化调用
-
android开发教程之自定义控件checkbox的样式示例
-
WPF自定义MenuItem样式的实现方法
-
WPF的ListView控件自定义布局用法实例
-
[WPF自定义控件库]好用的VisualTreeExtensions
-
[WPF自定义控件库]了解WPF的布局过程,并利用Measure为Expander添加动画
-
[WPF 自定义控件]自定义一个“传统”的 Validation.ErrorTemplate
-
[WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互
-
VS下WPF自定义控件的基本步骤和基本代码实现