How to customize Calendar in DateTimePicker Control?

给你一囗甜甜゛ 提交于 2019-12-17 19:55:37

问题


I think the question is simple and clear. The image bellow is my current progress.

As you can see, customized version is my extended DateTimePicker Control. The control changes button and border color depending on the Focused value. The dropped down calendar is the next thing I want to style.

I just don't know where to start because nothing seams to be working. I wouldn't change much at least border color, font color and etc...


回答1:


You have very few options. The drop-down calender is a MonthCalendar control, created dynamically by DTP when you click the dropdown button Destroyed again when the user dismisses it. MonthCalendar is one of the common controls, built into Windows, written in C++ and stored in comctl32.dll. Your app uses the v6.0 version, stored in the side-by-side cache (c:\windows\winsxs). The .NET class is just a wrapper, it doesn't change the way it looks or works.

Notable is that it changed a great deal between Windows versions, always something you have to watch out for, it is used in highly visible places in Windows. It is the first common control that a user ever interacts with when he installs Windows. And used in clock on the taskbar. Windows 10 is the first version that no longer does, the Win8 look-and-feel is frozen and unlikely to ever change again.

As noted, the dropdown is dynamically created. You can get a handle to the MonthCalendar window by sending the DTM_GETMONTHCAL message, do so in an event handler for the DropDown event. At that point the window handle is valid but the calendar not yet visible, the proper time to tinker with it.

From there you can send the MCM messages to configure the calendar. As you can tell, very slim pickings as far as styling goes. You have MCM_SETCALENDARBORDER to change the border thickness and MCM_SETCOLOR to alter colors. The latter only works if the visual style renderer is disabled, it is not in your app. Technically you can call SetWindowTheme() to disable the visual style renderer so MCM_SETCOLOR will work again. But that turns the clock back to the year 2000, it will look quite dinosauric.

That's all, not enough to ever make anybody happy. Consider embedding a WPF DatePicker to get more control over styling.




回答2:


There are a bunch of properties that affect the display of the calendar, such as:

  • CalendarFont
  • CalendarForeColor
  • CalendarMonthBackground
  • CalendarTitleBackColor

etc.

See MSDN for more info.

That said, the DateTimePicker control is (in)famous for not applying changes from these properties. It applies them only when visual styles on the whole form is turned off and then you get that ugly beveled look with applied colors of your choosing -- but still ugly.




回答3:


Had similar problem. It is not so bad after all. Mine DatePickerlooks a bit different, but it wont be a problem to adjust it for your needs.
First thing first - create a Resource Dictionary and add there all necessary styles for your project.
In my solution I used 2 styles:

  • The actual style for DatePicker;
  • Style to use custom button.

    Here are the codes:
    <!-- The IconButtonStyle -->
    <Style x:Key="IconButtonStyle"
               TargetType="{x:Type Button}">
        <!-- set some default values -->
        <Setter Property="Background"
                    Value="Transparent" />
        <Setter Property="BorderBrush"
                    Value="Transparent" />
        <Setter Property="VerticalAlignment"
                Value="Center" />
        <!-- set the visual tree of the control -->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <!-- here come the actual sub-controls -->
                    <Border x:Name="border"
                                Height="{TemplateBinding Height}"
                                Width="{TemplateBinding Width}"
                                SnapsToDevicePixels="True"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="1"
                                Padding="0"
                                CornerRadius="0,0,0,0">
                        <Border x:Name="innerBorder"
                                    SnapsToDevicePixels="True"
                                    BorderThickness="1"
                                    Padding="2"
                                    CornerRadius="0,0,0,0">
                            <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                  RecognizesAccessKey="True"
                                                  Margin="{TemplateBinding Padding}">
                                <ContentPresenter.Effect>
                                    <!-- give the content a bit of shadow -->
                                    <DropShadowEffect x:Name="shadow"
                                                          ShadowDepth="0"
                                                          Opacity="0.7"
                                                          BlurRadius="0" />
                                </ContentPresenter.Effect>
                                <ContentPresenter.RenderTransform>
                                    <!-- push the content a bit to the left and the top -->
                                    <TranslateTransform x:Name="translation"
                                                            X="0"
                                                            Y="0" />
                                </ContentPresenter.RenderTransform>
                            </ContentPresenter>
                        </Border>
                    </Border>
                    <ControlTemplate.Triggers>
                        <!-- 
                                the triggers define the reactions to various state
                                changes
                            -->
                        <Trigger Property="IsKeyboardFocused"
                                     Value="true">
                            <Setter TargetName="innerBorder"
                                        Property="BorderBrush"
                                        Value="Transparent" />
                            <Setter Property="Background"
                                        Value="Transparent" />
                        </Trigger>
                        <Trigger Property="IsMouseOver"
                                     Value="true">
                            <Setter Property="Background"
                                        Value="Transparent" />
                        </Trigger>
    
                        <!-- when the control is disabled, just let the background shine through -->
                        <Trigger Property="IsEnabled"
                                     Value="false">
                            <Setter Property="Opacity"
                                        Value="0.5" />
                        </Trigger>
                        <Trigger Property="IsPressed"
                                     Value="True">
                            <!-- This Trigger manages the Animation of the button's content and its shadow -->
                            <Trigger.EnterActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Duration="0:0:0"
                                                             To="0"
                                                             Storyboard.TargetName="shadow"
                                                             Storyboard.TargetProperty="(DropShadowEffect.ShadowDepth)" />
                                        <DoubleAnimation Duration="0:0:0"
                                                             To="0"
                                                             Storyboard.TargetName="translation"
                                                             Storyboard.TargetProperty="(TranslateTransform.X)" />
                                        <DoubleAnimation Duration="0:0:0"
                                                             To="0"
                                                             Storyboard.TargetName="translation"
                                                             Storyboard.TargetProperty="(TranslateTransform.Y)" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.EnterActions>
                            <Trigger.ExitActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Duration="0:0:0"
                                                             To="0"
                                                             Storyboard.TargetName="shadow"
                                                             Storyboard.TargetProperty="(DropShadowEffect.ShadowDepth)" />
                                        <DoubleAnimation Duration="0:0:0"
                                                             To="0"
                                                             Storyboard.TargetName="translation"
                                                             Storyboard.TargetProperty="(TranslateTransform.X)" />
                                        <DoubleAnimation Duration="0:0:0"
                                                             To="0"
                                                             Storyboard.TargetName="translation"
                                                             Storyboard.TargetProperty="(TranslateTransform.Y)" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.ExitActions>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    
    <!-- Customized Datepicker -->
    <Style x:Key="DatePicker" TargetType="{x:Type DatePicker}">
        <Setter Property="Foreground" Value="{StaticResource DarkGrayBrush}" />
        <Setter Property="Focusable" Value="True" />
        <Setter Property="VerticalAlignment" Value="Top" />
        <Setter Property="VerticalContentAlignment" Value="Top" />
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="IsTodayHighlighted" Value="True" />
        <Setter Property="SelectedDateFormat" Value="Short" />
        <Setter Property="Padding" Value="0" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <!--Set CalendarStyle to DatePickerCalendarStyle.-->
        <Setter Property="CalendarStyle"
          Value="{DynamicResource DatePickerCalendarStyle}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DatePicker}">
                    <Border BorderThickness="{TemplateBinding BorderThickness}"
                            Padding="{TemplateBinding Padding}"
                            CornerRadius="0" 
                            Background="Transparent">
                        <Grid x:Name="PART_Root"
                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="150" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <Button x:Name="PART_Button"                                     
                                    Grid.Column="1"
                                    Foreground="{TemplateBinding Foreground}"                                                                        
                                    Focusable="True"
                                    HorizontalAlignment="Left"
                                    Margin="-24,0,0,0"
                                    Grid.Row="0"
                                    Panel.ZIndex="2" 
                                    Padding="0" >
                                <Button.Style>
                                    <Style TargetType="{x:Type Button}" BasedOn="{StaticResource IconButtonStyle}">
                                        <Setter Property="Height" Value="23" />
                                        <Setter Property="Background" Value="Transparent" />
                                        <Style.Triggers>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="Background" Value="{StaticResource BlueFadedBrush}" />
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                </Button.Style>
                                <Image Height="15" VerticalAlignment="Top" >
                                    <Image.Style>
                                        <Style TargetType="{x:Type Image}">
                                            <Setter Property="Source" Value="/img/calendarBlue.png"/>                                            
                                            <Style.Triggers>
                                                <DataTrigger Binding="{Binding ElementName=PART_Button, Path=IsMouseOver}" Value="True">
                                                    <Setter Property="Source" Value="/img/calendarWhite.png"/>
                                                </DataTrigger>
                                            </Style.Triggers>
                                        </Style>
                                    </Image.Style>
                                </Image>
                            </Button>
                            <Border BorderBrush="{StaticResource BlueBrush}"
                                    BorderThickness="2"
                                    CornerRadius="0"
                                    Padding="0"
                                    Width="150"
                                    Height="23"
                                    Background="{StaticResource WhiteBrush}"
                                    Panel.ZIndex="1">
                                <DatePickerTextBox x:Name="PART_TextBox"                                               
                                                   Grid.Column="0"
                                                   Foreground="{TemplateBinding Foreground}"
                                                   Focusable="{TemplateBinding Focusable}"                                                   
                                                   HorizontalContentAlignment="Left"
                                                   Grid.Row="0"                                                                                                      
                                                   VerticalContentAlignment="Center" 
                                                   BorderThickness="0"
                                                   Background="Transparent"
                                                   Width="150" 
                                                   Padding="0">
                                    <!-- Watermark access -->
                                    <DatePickerTextBox.Style>
                                        <Style TargetType="DatePickerTextBox">
                                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
                                            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
                                            <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
                                            <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
                                            <Setter Property="Template">
                                                <Setter.Value>
                                                    <ControlTemplate TargetType="{x:Type DatePickerTextBox}">
                                                        <Grid>
                                                            <Grid.Resources>
                                                                <SolidColorBrush x:Key="WatermarkBrush" Color="#FFAAAAAA"/>
                                                            </Grid.Resources>
                                                            <VisualStateManager.VisualStateGroups>
                                                                <VisualStateGroup x:Name="CommonStates">
                                                                    <VisualStateGroup.Transitions>
                                                                        <VisualTransition GeneratedDuration="0"/>
                                                                        <VisualTransition GeneratedDuration="0:0:0.1" To="MouseOver"/>
                                                                    </VisualStateGroup.Transitions>
                                                                    <VisualState x:Name="Normal"/>
                                                                    <VisualState x:Name="MouseOver">
                                                                        <Storyboard>
                                                                            <ColorAnimation Duration="0" To="Transparent" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="ContentElement"/>
                                                                            <ColorAnimation Duration="0" To="Transparent" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="watermark_decorator"/>
                                                                        </Storyboard>
                                                                    </VisualState>
                                                                </VisualStateGroup>
                                                                <VisualStateGroup x:Name="WatermarkStates">
                                                                    <VisualStateGroup.Transitions>
                                                                        <VisualTransition GeneratedDuration="0"/>
                                                                    </VisualStateGroup.Transitions>
                                                                    <VisualState x:Name="Unwatermarked"/>
                                                                    <VisualState x:Name="Watermarked">
                                                                        <Storyboard>
                                                                            <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="ContentElement"/>
                                                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_Watermark"/>
                                                                        </Storyboard>
                                                                    </VisualState>
                                                                </VisualStateGroup>
                                                                <VisualStateGroup x:Name="FocusStates">
                                                                    <VisualStateGroup.Transitions>
                                                                        <VisualTransition GeneratedDuration="0"/>
                                                                    </VisualStateGroup.Transitions>
                                                                    <VisualState x:Name="Unfocused"/>
                                                                    <VisualState x:Name="Focused">
                                                                        <Storyboard>
                                                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisual"/>
                                                                        </Storyboard>
                                                                    </VisualState>
                                                                </VisualStateGroup>
                                                            </VisualStateManager.VisualStateGroups>
                                                            <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="1" Opacity="1" Padding="{TemplateBinding Padding}">
                                                                <Grid x:Name="WatermarkContent" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                                                                    <Border x:Name="ContentElement" BorderBrush="#FFFFFFFF" BorderThickness="0"/>
                                                                    <Border x:Name="watermark_decorator" BorderBrush="#FFFFFFFF" BorderThickness="0">
                                                                        <ContentControl x:Name="PART_Watermark" Focusable="False" IsHitTestVisible="False" Opacity="0" Padding="0">
                                                                            <ContentControl.Template>
                                                                                <ControlTemplate>
                                                                                    <TextBlock Text="dd/mm/aaaa" Margin="2,0,0,0"/>
                                                                                </ControlTemplate>
                                                                            </ContentControl.Template>
                                                                        </ContentControl>
                                                                    </Border>
                                                                    <ScrollViewer x:Name="PART_ContentHost" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="0" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                                                    <Border x:Name="FocusVisual" BorderBrush="#FF45D6FA" CornerRadius="1" IsHitTestVisible="False" Opacity="0"/>
                                                                </Grid>
                                                            </Border>
                                                        </Grid>
                                                    </ControlTemplate>
                                                </Setter.Value>
                                            </Setter>
                                        </Style>
                                    </DatePickerTextBox.Style>
                                    <!-- Watermark access Ends -->
                                </DatePickerTextBox>
                            </Border>
                            <Grid x:Name="PART_DisabledVisual"
                                  Grid.ColumnSpan="2"
                                  Grid.Column="0"
                                  IsHitTestVisible="False"
                                  Opacity="0"
                                  Grid.Row="0">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="Auto" />
                                </Grid.ColumnDefinitions>
                                <Rectangle Grid.Column="0"
                                        Fill="#A5FFFFFF"
                                        RadiusY="1"
                                        Grid.Row="0"
                                        RadiusX="1" />
                                <Rectangle Grid.Column="1"
                                         Fill="#A5FFFFFF"
                                         Height="18"
                                         Margin="3,0,3,0"
                                         RadiusY="1"
                                         Grid.Row="0"
                                         RadiusX="1"
                                         Width="19" />                                
                                <Popup x:Name="PART_Popup"                                       
                                         AllowsTransparency="True"                                       
                                         Placement="Bottom"
                                         PlacementTarget="{Binding ElementName=PART_TextBox}"
                                         StaysOpen="False" />                                
                            </Grid>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    The usage will look like:

    <DatePicker Style="{StaticResource DatePicker}" />
    


    来源:https://stackoverflow.com/questions/36152013/how-to-customize-calendar-in-datetimepicker-control

  • 易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
    该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!