zoukankan      html  css  js  c++  java
  • [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派生。(我将这个控件库定位为入门教材,所以越简单越好。)

    有必要的话可以设置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>
    

    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

  • 相关阅读:
    Python基础编程常用模块汇总
    博客目录
    网络编程
    python 对象
    python模块和规范开发
    python常用内置函数
    python递归函数和匿名函数
    python装饰器
    python迭代器,生成器,推导式
    python作用域
  • 原文地址:https://www.cnblogs.com/dino623/p/FunctionBar.html
Copyright © 2011-2022 走看看