简体   繁体   English

如何在DateTimePicker控件中自定义日历?

[英]How to customize Calendar in DateTimePicker Control?

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. 如您所见,自定义版本是我的扩展DateTimePicker控件。 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... 我至少不会改变边框颜色,字体颜色等...

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控件,当您单击用户解除它时再次单击下拉按钮时,由DTP动态创建。 MonthCalendar is one of the common controls , built into Windows, written in C++ and stored in comctl32.dll. MonthCalendar是Windows中内置的常用控件之一,用C ++编写并存储在comctl32.dll中。 Your app uses the v6.0 version, stored in the side-by-side cache (c:\\windows\\winsxs). 您的应用程序使用v6.0版本,存储在并行缓存中(c:\\ windows \\ winsxs)。 The .NET class is just a wrapper, it doesn't change the way it looks or works. .NET类只是一个包装器,它不会改变它的外观或工作方式。

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. 值得注意的是,它在Windows版本之间发生了很大变化,总是需要注意的事项,它在Windows中非常明显的地方使用。 It is the first common control that a user ever interacts with when he installs Windows. 它是用户在安装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. Windows 10是第一个不再使用的版本,Win8的外观被冻结,不太可能再次改变。

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. 您可以通过发送DTM_GETMONTHCAL消息获取MonthCalendar窗口的句柄,在DropDown事件的事件处理程序中执行此操作。 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. 从那里,您可以发送MCM消息来配置日历。 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. 您有MCM_SETCALENDARBORDER来更改边框粗细,MCM_SETCOLOR可以更改颜色。 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. 从技术上讲,您可以调用SetWindowTheme()来禁用视觉样式渲染器,以便MCM_SETCOLOR再次起作用。 But that turns the clock back to the year 2000, it will look quite dinosauric. 但是,这将时钟转回到2000年,它看起来会非常恐怖。

That's all, not enough to ever make anybody happy. 这就是全部,不足以让任何人开心。 Consider embedding a WPF DatePicker to get more control over styling. 考虑嵌入WPF DatePicker以获得对样式的更多控制。

There are a bunch of properties that affect the display of the calendar, such as: 有许多属性会影响日历的显示,例如:

  • CalendarFont CalendarFont
  • CalendarForeColor CalendarForeColor
  • CalendarMonthBackground CalendarMonthBackground
  • CalendarTitleBackColor CalendarTitleBackColor

etc. 等等

See MSDN for more info. 有关详细信息,请参阅MSDN

That said, the DateTimePicker control is (in)famous for not applying changes from these properties . 也就是说,DateTimePicker控件因未应用这些属性的更改而闻名。 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. 它仅在整个窗体上的视觉样式被关闭时应用它们,然后使用您选择的应用颜色获得丑陋的斜面外观 - 但仍然很难看。

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. 我的DatePicker看起来有点不同,但根据您的需要调整它不会有问题。
First thing first - create a Resource Dictionary and add there all necessary styles for your project. 首先要做的是 - 创建一个资源字典并为项目添加所有必需的样式。
In my solution I used 2 styles: 在我的解决方案中我使用了2种风格

  • The actual style for DatePicker; 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}" /> 
  • 声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

     
    粤ICP备18138465号  © 2020-2024 STACKOOM.COM