欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

[WPF自定义控件库]为Form和自定义Window添加FunctionBar

程序员文章站 2022-03-07 08:00:40
1. 前言 我常常看到同一个应用程序中的表单的按钮————也就是“确定”、“取消”那两个按钮————实现得千奇百怪,其实只要使用统一的Style起码就可以统一按钮的大小,而我喜欢更进一步将”确定“、”取消“或其它按钮封装进一个自定义控件里。 这篇文章介绍了另一种ItemsControl的实现方式,并 ......

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>

[WPF自定义控件库]为Form和自定义Window添加FunctionBar

这样做可以统一所有form的按钮。由于做得很简单,后期可以再按需要添加其他控件的样式。其实这种方式很像toolbar,我本来也考虑从toolbar派生functionbar,但考虑到toolbar本身的功能不少,而我只想要实现最简单的功能,所以直接从headereditemscontrol派生。(我将这个控件库定位为入门教材,所以越简单越好。)

有必要的话可以设置isdefaultiscancel属性,前者表示按钮会在表单点击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>

[WPF自定义控件库]为Form和自定义Window添加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. 源码

kino.toolkit.wpf_functionbar at master