如何在 UWP 中编写自定义选择器控件?

How do I write a custom picker control in UWP?

我一直在网上仔细梳理有关这方面的任何指导、讨论或经验,我想我可以肯定地说没有什么可找到的。

我们正在为 UWP 开发一组控件,我们计划将其开源并免费提供。我们正在构建的控件之一是 TimeSpanPicker 控件,它的外观和行为本质上与 TimePicker 控件相似,但它不限于一天中的某个时间(即 24 小时间隔),它允许用户编辑任意 TimeSpan.

根据我能够从 Windows 运行时 API 的可见元数据中拼凑出来的内容,使用内置的 TimePicker 控件作为参考,我意识到涉及以下类型的组件:

我意识到我需要模仿这种模式并为我们的选择器控件编写这三个组件,但我找不到有关这些部分如何组合在一起的信息,而且仅从 API 表面我也不知道认为有可能弄清楚。

具体来说,我想了解的主要是:

非常感谢任何指导!

我遇到了同样的问题,但在变通后,我做了以下操作来更改 TimePickerFlyout 的背景颜色和页脚按钮的大小以及我需要的其他样式。

导航至 C:\Program Files (x86)\Windows Kits\DesignTime\CommonConfiguration\Neutral\UAP.0.10240.0\Generic

(请注意,这可能会因您的 SDK 版本而异)

打开 generic.xaml 文件

TargetType="TimePickerFlyoutPresenter" 部分复制到您的 App.xaml,然后根据需要进行更改,所有弹出按钮都会相应更改。

复制此样式并将其放入App.xaml。

<!-- Default style for Windows.UI.Xaml.Controls.TimePickerFlyoutPresenter -->
<Style TargetType="TimePickerFlyoutPresenter">
    <Setter Property="Width" Value="242" />
    <Setter Property="MinWidth" Value="242" />
    <Setter Property="MaxHeight" Value="0" />
    <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
    <Setter Property="FontWeight" Value="Normal" />
    <Setter Property="IsTabStop" Value="False" />
    <Setter Property="VerticalAlignment" Value="Stretch" />
    <Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" />
    <Setter Property="AutomationProperties.AutomationId" Value="TimePickerFlyoutPresenter" />
    <Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundTransparentBrush}" />
    <Setter Property="BorderThickness" Value="{ThemeResource DateTimeFlyoutBorderThickness}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="TimePickerFlyoutPresenter">
                <Border x:Name="Background"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        MaxHeight="396">
                    <Grid x:Name="ContentPanel">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*" />
                            <RowDefinition Height="44" />
                        </Grid.RowDefinitions>

                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" x:Name="FirstPickerHostColumn" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" x:Name="SecondPickerHostColumn" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" x:Name="ThirdPickerHostColumn" />
                            </Grid.ColumnDefinitions>

                            <Rectangle x:Name="HighlightRect" Fill="{ThemeResource SystemControlHighlightListAccentLowBrush}" Grid.Column="0" Grid.ColumnSpan="5" VerticalAlignment="Center" Height="44" />

                            <Border x:Name="FirstPickerHost" Grid.Column="0" />
                            <Rectangle x:Name="FirstPickerSpacing" Fill="{ThemeResource SystemControlForegroundBaseLowBrush}" HorizontalAlignment="Center" Width="2" Grid.Column="1" />
                            <Border x:Name="SecondPickerHost" Grid.Column="2" />
                            <Rectangle x:Name="SecondPickerSpacing" Fill="{ThemeResource SystemControlForegroundBaseLowBrush}" HorizontalAlignment="Center" Width="2" Grid.Column="3" />
                            <Border x:Name="ThirdPickerHost" Grid.Column="4" />
                        </Grid>

                        <Grid Grid.Row="1" >
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Rectangle Height="2" VerticalAlignment="Top" Fill="{ThemeResource SystemControlForegroundBaseLowBrush}" Grid.ColumnSpan="2" />

                            <Button x:Name="AcceptButton" Grid.Column="0" Content="&#xE8FB;" FontFamily="{ThemeResource SymbolThemeFontFamily}" FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Style="{StaticResource DateTimePickerFlyoutButtonStyle}" Margin="0,2,0,0" />
                            <Button x:Name="DismissButton" Grid.Column="1" Content="&#xE711;" FontFamily="{ThemeResource SymbolThemeFontFamily}" FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Style="{StaticResource DateTimePickerFlyoutButtonStyle}" Margin="0,2,0,0" />
                        </Grid>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

因此,由于一些人要求我跟进此事,在 Jim Walker (MSFT) 的帮助下,我实际上最终能够解决所有这些问题。已经等了很长时间了,但我现在决定重新审视它,并最终完成我正在处理的 TimeSpanPickerTimeSpanEditor 控件。

https://github.com/IDeliverable/UwpControls

运行 TestHost 项目以查看两个控件的运行情况。

存储库还包含一些其他控件;包含 TimeSpanPickerTimeSpanEditor 控件的部分在这里:

https://github.com/IDeliverable/UwpControls/tree/master/src/IDeliverable.Controls.Uwp.TimeSpanPicker

对于任何对如何构建自定义选择器控件感兴趣的人来说,该代码有望成为一个非常好的示例,但这些控件也应该对需要向其应用程序添加 TimeSpan 编辑功能的任何人有用。我真的带着这些控件去了镇上,为细节和不明显的事情付出了汗水,比如可访问性、对多种输入模式(触摸、键盘、鼠标)的支持、系统主题合规性、完整的模板支持等。

这两个控件的文档目前正在制作中。

我计划很快将这些控件打包为 NuGet 包,但现在,您必须将它们作为源代码使用。我还将检查是否有兴趣将它们合并到 Window Community Toolkit.