xamldatepickeruwptimepicker

UWP - DatePicker and TimePicker customization


I would like to use DatePicker and TimePicker on the same line (horizontally). My problem is these controls are too wide. So I customized them to reduce the content but I can't reduce the width because the flyout is too wide. So I search a way to customize the flyout or to have a different size for the control and the flyout.

Here is my DatePicker style:

<Style TargetType="DatePicker">
    <Setter Property="Orientation" Value="Horizontal"/>
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
    <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
    <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/>
    <Setter Property="HorizontalAlignment" Value="Left"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="DatePicker">
                <StackPanel x:Name="LayoutRoot" Margin="{TemplateBinding Padding}">
                    <StackPanel.Resources>
                        <Style x:Key="DatePickerFlyoutButtonStyle" TargetType="Button">
                            <Setter Property="UseSystemFocusVisuals" Value="False" />
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="Button">
                                        <Grid Background="{TemplateBinding Background}">
                                            <VisualStateManager.VisualStateGroups>
                                                <VisualStateGroup x:Name="CommonStates">
                                                    <VisualState x:Name="Normal" />
                                                    <VisualState x:Name="PointerOver">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="BorderBrush">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseMediumBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlPageBackgroundAltMediumBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="Pressed">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="BorderBrush">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="Disabled">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="BorderBrush">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                </VisualStateGroup>
                                                <VisualStateGroup x:Name="FocusStates">
                                                    <VisualState x:Name="Focused">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListAccentLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                             Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="Unfocused" />
                                                    <VisualState x:Name="PointerFocused" />
                                                </VisualStateGroup>
                                            </VisualStateManager.VisualStateGroups>
                                            <ContentPresenter x:Name="ContentPresenter"
                                    BorderBrush="{TemplateBinding BorderBrush}"
                                    Background="{ThemeResource SystemControlBackgroundAltMediumLowBrush}"
                                    BorderThickness="{TemplateBinding BorderThickness}"
                                    Content="{TemplateBinding Content}"
                                    Foreground="{TemplateBinding Foreground}"
                                    HorizontalContentAlignment="Stretch"
                                    VerticalContentAlignment="Stretch"
                                    AutomationProperties.AccessibilityView="Raw"/>
                                        </Grid>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </StackPanel.Resources>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderContentPresenter"
                                             Storyboard.TargetProperty="Foreground">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FirstPickerSpacing"
                                             Storyboard.TargetProperty="Fill">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SecondPickerSpacing"
                                             Storyboard.TargetProperty="Fill">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ContentPresenter x:Name="HeaderContentPresenter"
                                      x:DeferLoadStrategy="Lazy"
                                      Visibility="Collapsed"
                                      Content="{TemplateBinding Header}"
                                      ContentTemplate="{TemplateBinding HeaderTemplate}"
                                      Margin="0,0,0,8"
                                      Foreground="{ThemeResource SystemControlForegroundBaseHighBrush}"
                                      AutomationProperties.AccessibilityView="Raw"
                                      BorderBrush="{TemplateBinding BorderBrush}"/>
                    <Button x:Name="FlyoutButton"
                            Style="{StaticResource DatePickerFlyoutButtonStyle}"
                            Foreground="{TemplateBinding Foreground}"
                            Background="{TemplateBinding Background}"
                            IsEnabled="{TemplateBinding IsEnabled}"
                            HorizontalAlignment="Stretch"
                            HorizontalContentAlignment="Stretch"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid x:Name="FlyoutButtonContentGrid"
                              HorizontalAlignment="Center">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" x:Name="DayColumn" />
                                <ColumnDefinition Width="Auto" x:Name="FirstSpacerColumn" />
                                <ColumnDefinition Width="Auto" x:Name="MonthColumn" />
                                <ColumnDefinition Width="Auto" x:Name="SecondSpacerColumn" />
                                <ColumnDefinition Width="Auto" x:Name="YearColumn" />
                            </Grid.ColumnDefinitions>

                            <TextBlock x:Name="DayTextBlock" Text="Day" TextAlignment="Center" Margin="4" FontFamily="{TemplateBinding FontFamily}" FontWeight="{TemplateBinding FontWeight}" FontSize="{TemplateBinding FontSize}" AutomationProperties.AccessibilityView="Raw"/>
                            <TextBlock x:Name="MonthTextBlock" Text="Month" TextAlignment="Left" Margin="4" FontFamily="{TemplateBinding FontFamily}" FontWeight="{TemplateBinding FontWeight}" FontSize="{TemplateBinding FontSize}" AutomationProperties.AccessibilityView="Raw"/>
                            <TextBlock x:Name="YearTextBlock" Text="Year" TextAlignment="Center" Margin="4" FontFamily="{TemplateBinding FontFamily}" FontWeight="{TemplateBinding FontWeight}" FontSize="{TemplateBinding FontSize}" AutomationProperties.AccessibilityView="Raw"/>

                        </Grid>
                    </Button>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Solution

  • To customize the flyout, we can edit the styles and templates of DatePickerFlyoutPresenter and TimePickerFlyoutPresenter. And we can find these styles in generic.xaml which is available in the \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.14393.0\Generic folder from a Windows SDK installation. For different SDK version, the path is different and the styles and resources might have different values. Using the default style for DatePickerFlyoutPresenter in 14393 for example:

    <!-- Default style for Windows.UI.Xaml.Controls.DatePickerFlyoutPresenter -->
    <Style TargetType="DatePickerFlyoutPresenter">
        <Setter Property="Width" Value="296" />
        <Setter Property="MinWidth" Value="296" />
        <Setter Property="MaxHeight" Value="398" />
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
        <Setter Property="FontWeight" Value="Normal" />
        <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
        <Setter Property="Background" Value="{ThemeResource DatePickerFlyoutPresenterBackground}" />
        <Setter Property="AutomationProperties.AutomationId" Value="DatePickerFlyoutPresenter" />
        <Setter Property="BorderBrush" Value="{ThemeResource DatePickerFlyoutPresenterBorderBrush}" />
        <Setter Property="BorderThickness" Value="{ThemeResource DateTimeFlyoutBorderThickness}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="DatePickerFlyoutPresenter">
                    <Border x:Name="Background"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        MaxHeight="398">
                        <Grid x:Name="ContentPanel">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid x:Name="PickerHostGrid">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="78*" x:Name="DayColumn" />
                                    <ColumnDefinition Width="Auto" x:Name="FirstSpacerColumn" />
                                    <ColumnDefinition Width="132*" x:Name="MonthColumn" />
                                    <ColumnDefinition Width="Auto" x:Name="SecondSpacerColumn" />
                                    <ColumnDefinition Width="78*" x:Name="YearColumn" />
                                </Grid.ColumnDefinitions>
                                <Rectangle x:Name="HighlightRect"
                                    Fill="{ThemeResource DatePickerFlyoutPresenterHighlightFill}"
                                    Grid.Column="0"
                                    Grid.ColumnSpan="5"
                                    VerticalAlignment="Center"
                                    Height="44" />
                                <Rectangle x:Name="FirstPickerSpacing"
                                    Fill="{ThemeResource DatePickerFlyoutPresenterSpacerFill}"
                                    HorizontalAlignment="Center"
                                    Width="2"
                                    Grid.Column="1" />
                                <Rectangle x:Name="SecondPickerSpacing"
                                    Fill="{ThemeResource DatePickerFlyoutPresenterSpacerFill}"
                                    HorizontalAlignment="Center"
                                    Width="2"
                                    Grid.Column="3" />
                            </Grid>
                            <Grid Grid.Row="1" Height="45" x:Name="AcceptDismissHostGrid">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>
                                <Rectangle Height="2"
                                    VerticalAlignment="Top"
                                    Fill="{ThemeResource DatePickerFlyoutPresenterSpacerFill}"
                                    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>
    

    We can change the Grid.ColumnDefinitions to reduce the width.

    But please note that although, there are Width and MinWidth properties in DatePickerFlyoutPresenter, but change them has no effect. DatePickerFlyoutPresenter's width is determined by DatePicker. They have the same width. If we changed DatePicker's width, the flyout will automatically adjust its width.

    Besides, in DatePickerFlyoutPresenter, we can't change ColumnDefinition's width to Auto like what you've done in DatePicker's style. Because in DatePickerFlyoutPresenter, "DayColumn", "MonthColumn" and "YearColumn" are populated with LoopingSelector, which uses a panel like Canvas inside. If we set the column's width to Auto, LoopingSelector's width will be zero and users can't see anything.

    So there may be not so much things we can customize, and we'd better set a fixed width for DatePicker like following to make sure users can see complete elements in the picker or in the picker's flyout.

    <DatePicker Width="200" MinWidth="0" />
    

    TimePicker is the same like DatePicker. If you want more flexibility, I'd suggest using a new custom control. Here is a blog about DatePicker calendar custom control for WinRT Xaml. You can refer to the blog and the source code on Codeplex to implement your own.