[WPF自定义控件库]为Form和自定义Window添加FunctionBar
1. 前言
我常常看到同一个应用程序中的表单的按钮————也就是“确定”、“取消”那两个按钮————实现得千奇百怪,其实只要使用统一的style起码就可以统一按钮的大小,而我喜欢更进一步将”确定“、”取消“或其它按钮封装进一个自定义控件里。
这篇文章介绍了另一种itemscontrol的实现方式,并使用它为表单及自定义window添加常用的按钮及其它功能。
2. 为form添加functionbar
本来打算派生自toolbar,或者参考uwp的commandbar,但最后决定参考mahapps.metro的windowcommands创建了formfunctionbar,它继承自headereditemscontrol,代码里没有任何功能,defaultstyle如下:
<style targettype="button" x:key="formfunctionbarbuttonbase"> <setter property="minwidth" value="48" /> <setter property="margin" value="4,0,0,0" /> <style.triggers> <trigger property="isdefault" value="true"> <setter property="minwidth" value="96" /> </trigger> </style.triggers> </style> <style x:key="formfunctionbarextendedbutton" targettype="local:extendedbutton" basedon="{staticresource formfunctionbarbuttonbase}" /> <style x:key="formfunctionbarbutton" targettype="button" basedon="{staticresource formfunctionbarbuttonbase}" /> <style targettype="{x:type local:formfunctionbar}"> <setter property="focusvisualstyle" value="{x:null}" /> <setter property="focusable" value="false" /> <setter property="istabstop" value="false" /> <setter property="margin" value="0" /> <setter property="padding" value="12,0,12,12" /> <setter property="horizontalcontentalignment" value="right" /> <setter property="template"> <setter.value> <controltemplate targettype="local:formfunctionbar"> <controltemplate.resources> <style basedon="{staticresource formfunctionbarbutton}" targettype="{x:type button}" /> <style basedon="{staticresource formfunctionbarextendedbutton}" targettype="{x:type local:extendedbutton}" /> </controltemplate.resources> <grid margin="{templatebinding padding}"> <contentpresenter content="{templatebinding header}" contenttemplate="{templatebinding headertemplate}" horizontalalignment="left" /> <itemspresenter horizontalalignment="{templatebinding horizontalcontentalignment}" grid.column="1" /> </grid> </controltemplate> </setter.value> </setter> <setter property="itemspanel"> <setter.value> <itemspaneltemplate> <stackpanel orientation="horizontal" /> </itemspaneltemplate> </setter.value> </setter> </style>
这是itemscontrol的另一种实现方式,放进formfunctionbar的button及kinobutton都会自动应用defaultstyle预设的样式。然后在form中添加functionbar属性,并在控件底部放一个placeholder:
<grid> <grid.rowdefinitions> <rowdefinition height="auto" /> <rowdefinition /> <rowdefinition height="auto" /> </grid.rowdefinitions> <local:pagetitle content="{templatebinding header}" contenttemplate="{templatebinding headertemplate}" /> <local:extendedscrollviewer grid.row="1" padding="{templatebinding padding}"> <itemspresenter snapstodevicepixels="true" uselayoutrounding="true" /> </local:extendedscrollviewer> <contentpresenter content="{templatebinding functionbar}" grid.row="2" /> </grid>
最终formfunctionbar的使用方式如下:
<kino:form> <kino:form.functionbar> <kino:formfunctionbar> <button content="ok" click="onok" isdefault="true" /> <button content="cancel" iscancel="true" click="oncancel" /> </kino:formfunctionbar> </kino:form.functionbar> </kino:form>
这样做可以统一所有form的按钮。由于做得很简单,后期可以再按需要添加其他控件的样式。其实这种方式很像toolbar,我本来也考虑从toolbar派生functionbar,但考虑到toolbar本身的功能不少,而我只想要实现最简单的功能,所以直接从headereditemscontrol派生。(我将这个控件库定位为入门教材,所以越简单越好。)
有必要的话可以设置isdefault和iscancel属性,前者表示按钮会在表单点击enter
时触发,后者表示按钮会在表单点击esc
时触发。在formfunctionbar我通过trigger设置了isdefault=true的按钮比其它按钮更长。
3. 为自定义window添加按钮
为自定义window在标题栏添加一些按钮也是个常见的需求,原理和formfunctionbar一样,只需要在自定义的window的适当位置放置一个placeholder,然后把windowfunctionbar放进去,使用方式如下:
<kino:extendedwindow.functionbar> <kino:windowfunctionbar> <button content="dino.c" /> <separator /> <menu> <menuitem header="发送反馈"> <menuitem header="报告问题" ischeckable="true" /> <menuitem header="提供反馈" ischeckable="true" /> <separator /> <menuitem header="设置..." /> </menuitem> </menu> <button tooltip="help"> <grid uselayoutrounding="true"> <path data="some data" width="12" height="12" uselayoutrounding="true" verticalalignment="center" horizontalalignment="center" fill="white" /> </grid> </button> </kino:windowfunctionbar> </kino:extendedwindow.functionbar>
windowfunctionbar的defaultstyle和formfunctionbar大同小异,只是多了一些常用控件(如menu、separator)的样式,这里不一一展示。
4. 结语
functionbar展示了另一种自定义控件的方式:它本身基本上没有功能,只是方便添加items并为为items套用style。如果派生自toolbar的话可以使用overflowitems功能,这很有趣,但现在还用不到所以没做。将来把functionbar添加到listboxitem之类的地方可能会需要。
有必要的话还可以添加多个functionbar,如window上可以添加leftwindowcommands、rightwindowcommands等各个功能区域,我工作上没遇到这种需求为求简单就只添加了一个功能区。
其实实现functionbar最大的难题是命名,我在commandbar、actionbar、toolbar、buttonsbar等名称之间由于了很久,根据反馈也许还是会修改。
5. 参考
mahapps.metro_windowcommands.cs at master
button.isdefault property (system.windows.controls) microsoft docs
button.iscancel property (system.windows.controls) microsoft docs
6. 源码
上一篇: photoshop 打造绚丽的光束翅膀
下一篇: Nodejs异步流程框架async的方法