[WPF自定义控件库]为Form和自定义Window添加FunctionBar
Posted dino623
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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. 源码
Kino.Toolkit.Wpf_FunctionBar at master
以上是关于[WPF自定义控件库]为Form和自定义Window添加FunctionBar的主要内容,如果未能解决你的问题,请参考以下文章