WPF中Expander的用法和控件模板详解
程序员文章站
2023-11-14 17:07:58
一、Expander的用法 在WPF中,Expander是一个很实用的复合控件,可以很方便的实现下拉菜单和导航栏等功能。先介绍简单的用法,而后分析他的控件模板。 可以看到Expander主要分为头部和内容两部分,展开时才显示内容,而内容部分可以存放丰富的内容 效果图: 二、控件模板 如何获取控件本身 ......
一、expander的用法
在wpf中,expander是一个很实用的复合控件,可以很方便的实现下拉菜单和导航栏等功能。先介绍简单的用法,而后分析他的控件模板。
<window.resources> <resourcedictionary> <style x:key="expander.stackpanel.style" targettype="frameworkelement"> <setter property="maxwidth" value="80"></setter> <setter property="minwidth" value="50"></setter> <setter property="horizontalalignment" value="left"></setter> </style> </resourcedictionary> </window.resources> <grid> <expander style="{dynamicresource expanderstyle}" header="头部"> <stackpanel> <button style="{staticresource expander.stackpanel.style}">内容1</button> <radiobutton style="{staticresource expander.stackpanel.style}">内容2</radiobutton> <textbox style="{staticresource expander.stackpanel.style}">内容3</textbox> <textblock style="{staticresource expander.stackpanel.style}">内容4</textblock> </stackpanel> </expander> </grid>
可以看到expander主要分为头部和内容两部分,展开时才显示内容,而内容部分可以存放丰富的内容
效果图:
二、控件模板
如何获取控件本身默认的控件模板请看我的另一篇文章:
因为控件模板比较复杂,先看大概的构成:
再看看主样式部分(expandersytle)的构成:
再看向下展开时头部的样式构成:
如下为我标注了注释的完整控件模板代码:
<solidcolorbrush x:key="expander.mouseover.circle.stroke" color="#ff5593ff"/> <solidcolorbrush x:key="expander.mouseover.circle.fill" color="#fff3f9ff"/> <solidcolorbrush x:key="expander.mouseover.arrow.stroke" color="#ff000000"/> <solidcolorbrush x:key="expander.pressed.circle.stroke" color="#ff3c77dd"/> <solidcolorbrush x:key="expander.pressed.circle.fill" color="#ffd9ecff"/> <solidcolorbrush x:key="expander.pressed.arrow.stroke" color="#ff000000"/> <solidcolorbrush x:key="expander.disabled.circle.stroke" color="#ffbcbcbc"/> <solidcolorbrush x:key="expander.disabled.circle.fill" color="#ffe6e6e6"/> <solidcolorbrush x:key="expander.disabled.arrow.stroke" color="#ff707070"/> <solidcolorbrush x:key="expander.static.circle.fill" color="#ffffffff"/> <solidcolorbrush x:key="expander.static.circle.stroke" color="#ff333333"/> <solidcolorbrush x:key="expander.static.arrow.stroke" color="#ff333333"/> <!--expanddirection=right,即向右展开时的头部样式--> <style x:key="expanderrightheaderstyle" targettype="{x:type togglebutton}"> <setter property="template"> <setter.value> <controltemplate targettype="{x:type togglebutton}"> <border padding="{templatebinding padding}"> <grid background="transparent" snapstodevicepixels="false"> <grid.rowdefinitions> <rowdefinition height="19"/> <rowdefinition height="*"/> </grid.rowdefinitions> <grid> <grid.layouttransform> <transformgroup> <transformgroup.children> <transformcollection> <rotatetransform angle="-90"/> </transformcollection> </transformgroup.children> </transformgroup> </grid.layouttransform> <ellipse x:name="circle" fill="yellow" horizontalalignment="center" height="19" stroke="yellow" verticalalignment="center" width="19"/> <path x:name="arrow" data="m 1,1.5 l 4.5,5 l 8,1.5" horizontalalignment="center" snapstodevicepixels="false" stroke="{staticresource expander.static.arrow.stroke}" strokethickness="2" verticalalignment="center"/> </grid> <contentpresenter horizontalalignment="center" margin="0,4,0,0" grid.row="1" recognizesaccesskey="true" snapstodevicepixels="true" verticalalignment="top"/> </grid> </border> <controltemplate.triggers> <trigger property="ischecked" value="true"> <setter property="data" targetname="arrow" value="m 1,4.5 l 4.5,1 l 8,4.5"/> </trigger> <trigger property="ismouseover" value="true"> <setter property="stroke" targetname="circle" value="{staticresource expander.mouseover.circle.stroke}"/> <setter property="fill" targetname="circle" value="{staticresource expander.mouseover.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.mouseover.arrow.stroke}"/> </trigger> <trigger property="ispressed" value="true"> <setter property="stroke" targetname="circle" value="{staticresource expander.pressed.circle.stroke}"/> <setter property="strokethickness" targetname="circle" value="1.5"/> <setter property="fill" targetname="circle" value="{staticresource expander.pressed.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.pressed.arrow.stroke}"/> </trigger> <trigger property="isenabled" value="false"> <setter property="stroke" targetname="circle" value="{staticresource expander.disabled.circle.stroke}"/> <setter property="fill" targetname="circle" value="{staticresource expander.disabled.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.disabled.arrow.stroke}"/> </trigger> </controltemplate.triggers> </controltemplate> </setter.value> </setter> </style> <!--expanddirection=up,即向上展开时的头部样式--> <style x:key="expanderupheaderstyle" targettype="{x:type togglebutton}"> <setter property="template"> <setter.value> <controltemplate targettype="{x:type togglebutton}"> <border padding="{templatebinding padding}"> <grid background="transparent" snapstodevicepixels="false"> <grid.columndefinitions> <columndefinition width="19"/> <columndefinition width="*"/> </grid.columndefinitions> <grid> <grid.layouttransform> <transformgroup> <transformgroup.children> <transformcollection> <rotatetransform angle="180"/> </transformcollection> </transformgroup.children> </transformgroup> </grid.layouttransform> <ellipse x:name="circle" fill="{staticresource expander.static.circle.fill}" horizontalalignment="center" height="19" stroke="{staticresource expander.static.circle.stroke}" verticalalignment="center" width="19"/> <path x:name="arrow" data="m 1,1.5 l 4.5,5 l 8,1.5" horizontalalignment="center" snapstodevicepixels="false" stroke="{staticresource expander.static.arrow.stroke}" strokethickness="2" verticalalignment="center"/> </grid> <contentpresenter grid.column="1" horizontalalignment="left" margin="4,0,0,0" recognizesaccesskey="true" snapstodevicepixels="true" verticalalignment="center"/> </grid> </border> <controltemplate.triggers> <trigger property="ischecked" value="true"> <setter property="data" targetname="arrow" value="m 1,4.5 l 4.5,1 l 8,4.5"/> </trigger> <trigger property="ismouseover" value="true"> <setter property="stroke" targetname="circle" value="{staticresource expander.mouseover.circle.stroke}"/> <setter property="fill" targetname="circle" value="{staticresource expander.mouseover.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.mouseover.arrow.stroke}"/> </trigger> <trigger property="ispressed" value="true"> <setter property="stroke" targetname="circle" value="{staticresource expander.pressed.circle.stroke}"/> <setter property="strokethickness" targetname="circle" value="1.5"/> <setter property="fill" targetname="circle" value="{staticresource expander.pressed.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.pressed.arrow.stroke}"/> </trigger> <trigger property="isenabled" value="false"> <setter property="stroke" targetname="circle" value="{staticresource expander.disabled.circle.stroke}"/> <setter property="fill" targetname="circle" value="{staticresource expander.disabled.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.disabled.arrow.stroke}"/> </trigger> </controltemplate.triggers> </controltemplate> </setter.value> </setter> </style> <!--expanddirection=left,即向左展开时的头部样式--> <style x:key="expanderleftheaderstyle" targettype="{x:type togglebutton}"> <setter property="template"> <setter.value> <controltemplate targettype="{x:type togglebutton}"> <border padding="{templatebinding padding}"> <grid background="transparent" snapstodevicepixels="false"> <grid.rowdefinitions> <rowdefinition height="19"/> <rowdefinition height="*"/> </grid.rowdefinitions> <grid> <grid.layouttransform> <transformgroup> <transformgroup.children> <transformcollection> <rotatetransform angle="90"/> </transformcollection> </transformgroup.children> </transformgroup> </grid.layouttransform> <ellipse x:name="circle" fill="{staticresource expander.static.circle.fill}" horizontalalignment="center" height="19" stroke="{staticresource expander.static.circle.stroke}" verticalalignment="center" width="19"/> <path x:name="arrow" data="m 1,1.5 l 4.5,5 l 8,1.5" horizontalalignment="center" snapstodevicepixels="false" stroke="{staticresource expander.static.arrow.stroke}" strokethickness="2" verticalalignment="center"/> </grid> <contentpresenter horizontalalignment="center" margin="0,4,0,0" grid.row="1" recognizesaccesskey="true" snapstodevicepixels="true" verticalalignment="top"/> </grid> </border> <controltemplate.triggers> <trigger property="ischecked" value="true"> <setter property="data" targetname="arrow" value="m 1,4.5 l 4.5,1 l 8,4.5"/> </trigger> <trigger property="ismouseover" value="true"> <setter property="stroke" targetname="circle" value="{staticresource expander.mouseover.circle.stroke}"/> <setter property="fill" targetname="circle" value="{staticresource expander.mouseover.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.mouseover.arrow.stroke}"/> </trigger> <trigger property="ispressed" value="true"> <setter property="stroke" targetname="circle" value="{staticresource expander.pressed.circle.stroke}"/> <setter property="strokethickness" targetname="circle" value="1.5"/> <setter property="fill" targetname="circle" value="{staticresource expander.pressed.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.pressed.arrow.stroke}"/> </trigger> <trigger property="isenabled" value="false"> <setter property="stroke" targetname="circle" value="{staticresource expander.disabled.circle.stroke}"/> <setter property="fill" targetname="circle" value="{staticresource expander.disabled.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.disabled.arrow.stroke}"/> </trigger> </controltemplate.triggers> </controltemplate> </setter.value> </setter> </style> <!--expanddirection=down,即向下展开时的头部样式(一般默认向下展开)--> <style x:key="expanderdownheaderstyle" targettype="{x:type togglebutton}"> <setter property="template"> <setter.value> <controltemplate targettype="{x:type togglebutton}"> <border padding="{templatebinding padding}"> <grid background="transparent" snapstodevicepixels="false"> <grid.columndefinitions> <columndefinition width="19"/> <columndefinition width="*"/> <!--可变部分自适应存放文字--> </grid.columndefinitions> <!--下拉头部(ellipse和path组成圆圈箭头图标 contentpresenter为文字)--> <ellipse x:name="circle" fill="{staticresource expander.static.circle.fill}" horizontalalignment="center" height="19" stroke="{staticresource expander.static.circle.stroke}" verticalalignment="center" width="19"/> <path x:name="arrow" data="m 1,1.5 l 4.5,5 l 8,1.5" horizontalalignment="center" snapstodevicepixels="false" stroke="{staticresource expander.static.arrow.stroke}" strokethickness="2" verticalalignment="center"/> <contentpresenter grid.column="1" horizontalalignment="left" margin="4,0,0,0" recognizesaccesskey="true" snapstodevicepixels="true" verticalalignment="center"/> </grid> </border> <controltemplate.triggers> <!--选中时向下箭头变为为向上箭头--> <trigger property="ischecked" value="true"> <setter property="data" targetname="arrow" value="m 1,4.5 l 4.5,1 l 8,4.5"/> </trigger> <trigger property="ismouseover" value="true"> <setter property="stroke" targetname="circle" value="{staticresource expander.mouseover.circle.stroke}"/> <setter property="fill" targetname="circle" value="{staticresource expander.mouseover.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.mouseover.arrow.stroke}"/> </trigger> <trigger property="ispressed" value="true"> <setter property="stroke" targetname="circle" value="{staticresource expander.pressed.circle.stroke}"/> <setter property="strokethickness" targetname="circle" value="1.5"/> <setter property="fill" targetname="circle" value="{staticresource expander.pressed.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.pressed.arrow.stroke}"/> </trigger> <trigger property="isenabled" value="false"> <setter property="stroke" targetname="circle" value="{staticresource expander.disabled.circle.stroke}"/> <setter property="fill" targetname="circle" value="{staticresource expander.disabled.circle.fill}"/> <setter property="stroke" targetname="arrow" value="{staticresource expander.disabled.arrow.stroke}"/> </trigger> </controltemplate.triggers> </controltemplate> </setter.value> </setter> </style> <!--键盘焦点样式--> <style x:key="expanderheaderfocusvisual"> <setter property="control.template"> <setter.value> <controltemplate> <border> <rectangle margin="0" snapstodevicepixels="true" stroke="black" strokethickness="1" strokedasharray="1 2"/> </border> </controltemplate> </setter.value> </setter> </style> <!--expander样式--> <style x:key="expanderstyle" targettype="{x:type expander}"> <setter property="foreground" value="{dynamicresource {x:static systemcolors.controltextbrushkey}}"/> <setter property="background" value="transparent"/> <setter property="horizontalcontentalignment" value="stretch"/> <setter property="verticalcontentalignment" value="stretch"/> <setter property="borderbrush" value="transparent"/> <setter property="borderthickness" value="1"/> <setter property="template"> <setter.value> <!--控件模板--> <controltemplate targettype="{x:type expander}"> <border borderbrush="{templatebinding borderbrush}" borderthickness="{templatebinding borderthickness}" background="{templatebinding background}" cornerradius="3" snapstodevicepixels="true"> <dockpanel> <!--头部标题--> <togglebutton x:name="headersite" contenttemplate="{templatebinding headertemplate}" contenttemplateselector="{templatebinding headertemplateselector}" content="{templatebinding header}" dockpanel.dock="top" foreground="{templatebinding foreground}" fontweight="{templatebinding fontweight}" focusvisualstyle="{staticresource expanderheaderfocusvisual}" fontstyle="{templatebinding fontstyle}" fontstretch="{templatebinding fontstretch}" fontsize="{templatebinding fontsize}" fontfamily="{templatebinding fontfamily}" horizontalcontentalignment="{templatebinding horizontalcontentalignment}" ischecked="{binding isexpanded, mode=twoway, relativesource={relativesource templatedparent}}" margin="1" minwidth="0" minheight="0" padding="{templatebinding padding}" style="{staticresource expanderdownheaderstyle}" verticalcontentalignment="{templatebinding verticalcontentalignment}"/> <!--下拉内容--> <contentpresenter x:name="expandsite" dockpanel.dock="bottom" focusable="false" horizontalalignment="{templatebinding horizontalcontentalignment}" margin="{templatebinding padding}" visibility="collapsed" verticalalignment="{templatebinding verticalcontentalignment}"/> </dockpanel> </border> <!--触发器--> <controltemplate.triggers> <!--内容展开则显示隐藏内容--> <trigger property="isexpanded" value="true"> <setter property="visibility" targetname="expandsite" value="visible"/> </trigger> <!--向左、右、上展开修改dockpanel中标题和内容布局方式实现--> <trigger property="expanddirection" value="right"> <setter property="dockpanel.dock" targetname="expandsite" value="right"/> <setter property="dockpanel.dock" targetname="headersite" value="left"/> <setter property="style" targetname="headersite" value="{staticresource expanderrightheaderstyle}"/> </trigger> <trigger property="expanddirection" value="up"> <setter property="dockpanel.dock" targetname="expandsite" value="top"/> <setter property="dockpanel.dock" targetname="headersite" value="bottom"/> <setter property="style" targetname="headersite" value="{staticresource expanderupheaderstyle}"/> </trigger> <trigger property="expanddirection" value="left"> <setter property="dockpanel.dock" targetname="expandsite" value="left"/> <setter property="dockpanel.dock" targetname="headersite" value="right"/> <setter property="style" targetname="headersite" value="{staticresource expanderleftheaderstyle}"/> </trigger> <trigger property="isenabled" value="false"> <setter property="foreground" value="{dynamicresource {x:static systemcolors.graytextbrushkey}}"/> </trigger> </controltemplate.triggers> </controltemplate> </setter.value> </setter> </style>
知道了expander默认控件模板的构成就可以根据需要修改,轻松构建自定义的导航栏等功能(建议只修改需要修改的部分)。
上一篇: C# 可空类型的具体使用
推荐阅读
-
WPF中Expander的用法和控件模板详解
-
Angular中$cacheFactory的作用和用法实例详解
-
PHP中__get()和__set()的用法实例详解
-
Python中 Global和Nonlocal的用法详解
-
Linux中 sed 和 awk的用法详解
-
JavaScript中的Repaint和Reflow用法详解
-
Content-Type中application/x-www-form-urlencoded和multipart/form-data的区别及用法详解
-
ES6中Array.find()和findIndex()函数的用法详解
-
Oracle中的INSTR,NVL和SUBSTR函数的用法详解
-
Python中.join()和os.path.join()两个函数的用法详解