一.前言
申明: WPF 自定义控件与样式是一个系列文章, 前后是有些关联的, 但大多是按照由简到繁的顺序逐步发布的等, 若有不明白的地方可以参考本系列前面的文章, 文末附有部分文章链接.
本文主要内容:
日历控件 Calendar 自定义样式;
日期控件 DatePicker 自定义样式, 及 Label 标签, 水印, 清除日期功能扩展;
二.Calendar 自定义样式
先看看效果:
从上面图可以看出, 日历的显示其实有三种状态, 如下面的分解图:
"日" 部分的显示;
"月" 部分的显示;
"年" 部分的显示;
因此一个完整的日历, 就包含多个部分, 首先是 "日" 按钮的样式:
- <!--Day 按钮样式 -->
- <Style x:Key="CalendarDayButtonStyle" TargetType="{x:Type CalendarDayButton}">
- <Setter Property="MinWidth" Value="28" />
- <Setter Property="MinHeight" Value="5" />
- <Setter Property="FontFamily" Value="{StaticResource FontFamily}" />
- <Setter Property="HorizontalContentAlignment" Value="Center" />
- <Setter Property="VerticalContentAlignment" Value="Center" />
- <Setter Property="Background" Value="Transparent" />
- <Setter Property="Foreground" Value="{StaticResource TextForeground}" />
- <Setter Property="Margin" Value="0" />
- <Setter Property="IsTabStop" Value="False" />
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="{x:Type CalendarDayButton}">
- <Grid x:Name="Grid" Margin="{TemplateBinding Margin}">
- <Border x:Name="Bg" Background="{TemplateBinding Background}" />
- <ContentPresenter x:Name="NormalText" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
- Margin="5,2,5,2" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
- TextElement.Foreground="{TemplateBinding Foreground}" />
- </Grid>
- <ControlTemplate.Triggers>
- <Trigger Property="IsSelected" Value="True">
- <Setter Property="Background" Value="{StaticResource ItemSelectedBackground}"></Setter>
- <Setter Property="Foreground" Value="{StaticResource ItemSelectedForeground}"></Setter>
- </Trigger>
- <Trigger Property="IsToday" Value="True">
- <Setter Property="Background" Value="{StaticResource ItemHighlighteBackground}"></Setter>
- <Setter Property="Foreground" Value="{StaticResource ItemHighlighteForeground}"></Setter>
- </Trigger>
- <Trigger Property="IsMouseOver" Value="True">
- <Setter Property="Background" Value="{StaticResource ItemMouseOverBackground}"></Setter>
- <Setter Property="Foreground" Value="{StaticResource ItemMouseOverForeground}"></Setter>
- </Trigger>
- <!-- 不可用日期 -->
- <Trigger Property="IsBlackedOut" Value="True">
- <Setter Property="Opacity" Value="{StaticResource DisableOpacity}" TargetName="Grid"></Setter>
- </Trigger>
- <!-- 不在当月的日期 -->
- <Trigger Property="IsInactive" Value="True">
- <Setter Property="Opacity" Value="0.65" TargetName="Grid"></Setter>
- </Trigger>
- <Trigger Property="IsEnabled" Value="False">
- <Setter Property="Opacity" Value="{StaticResource DisableOpacity}" TargetName="Grid"></Setter>
- </Trigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
日历日期面板样式:
- <!-- 日历日期面板样式 -->
- <Style x:Key="CalendarItemStyle" TargetType="{x:Type CalendarItem}">
- <Setter Property="Margin" Value="0,1,0,1" />
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="{x:Type CalendarItem}">
- <ControlTemplate.Resources>
- <!-- 头部星期样式 -->
- <DataTemplate x:Key="{x:Static CalendarItem.DayTitleTemplateResourceKey}">
- <TextBlock Text="{Binding}" FontWeight="Bold" FontFamily="{StaticResource FontFamily}" Foreground="{StaticResource PressedForeground}"
- FontSize="{StaticResource HeaderFontSize}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,6,0,6" Opacity="0.8" />
- </DataTemplate>
- </ControlTemplate.Resources>
- <Grid x:Name="PART_Root">
- <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" Background="{TemplateBinding Background}" Margin="{TemplateBinding Margin}">
- <Grid Margin="2">
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="Auto" />
- </Grid.ColumnDefinitions>
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto" />
- <RowDefinition Height="*" />
- </Grid.RowDefinitions>
- <!--Header-->
- <Grid Grid.Row="0" HorizontalAlignment="Stretch" Background="{StaticResource HeaderBackground}">
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="*"/>
- <ColumnDefinition Width="2*"/>
- <ColumnDefinition Width="*"/>
- </Grid.ColumnDefinitions>
- <local:FButton x:Name="PART_HeaderButton" FontWeight="Bold" Style="{StaticResource FButton_Transparency}"
- Focusable="False" Grid.Column="1" FIcon="{x:Null}"/>
- <local:FButton x:Name="PART_PreviousButton" Style="{StaticResource FButton_Transparency}"
- Focusable="False" Grid.Column="0" FIconSize="18" Content=""FIcon=""/>
- <local:FButton x:Name="PART_NextButton" Style="{StaticResource FButton_Transparency}"
- Focusable="False" Grid.Column="2" FIconSize="18" Content=""FIcon=""/>
- </Grid>
- <!--PART_MonthView-->
- <Grid x:Name="PART_MonthView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="6,1,6,6" Grid.Row="1" Visibility="Visible">
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="*" />
- <ColumnDefinition Width="*" />
- <ColumnDefinition Width="*" />
- <ColumnDefinition Width="*" />
- <ColumnDefinition Width="*" />
- <ColumnDefinition Width="*" />
- <ColumnDefinition Width="*" />
- </Grid.ColumnDefinitions>
- <Grid.RowDefinitions>
- <RowDefinition Height="*" />
- <RowDefinition Height="*" />
- <RowDefinition Height="*" />
- <RowDefinition Height="*" />
- <RowDefinition Height="*" />
- <RowDefinition Height="*" />
- <RowDefinition Height="*" />
- </Grid.RowDefinitions>
- </Grid>
- <!--PART_YearView-->
- <Grid x:Name="PART_YearView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="6,10,6,10" Grid.Row="1" Visibility="Hidden">
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="*" />
- <ColumnDefinition Width="*" />
- <ColumnDefinition Width="*" />
- <ColumnDefinition Width="*" />
- </Grid.ColumnDefinitions>
- <Grid.RowDefinitions>
- <RowDefinition Height="*" />
- <RowDefinition Height="*" />
- <RowDefinition Height="*" />
- </Grid.RowDefinitions>
- </Grid>
- </Grid>
- </Border>
- </Grid>
- <ControlTemplate.Triggers>
- <Trigger Property="IsEnabled" Value="False">
- <Setter Property="Opacity" TargetName="PART_Root" Value="{StaticResource DisableOpacity}" />
- </Trigger>
- <DataTrigger Binding="{Binding DisplayMode, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Calendar}}}" Value="Year">
- <Setter Property="Visibility" TargetName="PART_MonthView" Value="Hidden" />
- <Setter Property="Visibility" TargetName="PART_YearView" Value="Visible" />
- </DataTrigger>
- <!--Decade 美 ['d?ked] n. 十年, 十年期; 十 -->
- <DataTrigger Binding="{Binding DisplayMode, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Calendar}}}" Value="Decade">
- <Setter Property="Visibility" TargetName="PART_MonthView" Value="Hidden" />
- <Setter Property="Visibility" TargetName="PART_YearView" Value="Visible" />
- </DataTrigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
年月按钮样式:
<!-- 年, 月按钮样式 --> <Style x:Key="CalendarButtonStyle" TargetType="{x:Type CalendarButton}"> <Setter Property="Background" Value="Transparent" /> <Setter Property="MinWidth" Value="40" /> <Setter Property="MinHeight" Value="42" /> <Setter Property="FontSize" Value="{StaticResource FontSize}" /> <Setter Property="FontFamily" Value="{StaticResource FontFamily}" /> <Setter Property="HorizontalContentAlignment" Value="Center" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type CalendarButton}"> <Grid x:Name="Grid" Margin="{TemplateBinding Margin}"> <Border x:Name="Bg" Background="{TemplateBinding Background}" /> <ContentPresenter x:Name="NormalText" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="5,2,5,2" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" TextElement.Foreground="{TemplateBinding Foreground}" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsFocused" Value="True"> <Setter Property="Background" Value="{StaticResource ItemSelectedBackground}"></Setter> <Setter Property="Foreground" Value="{StaticResource ItemSelectedForeground}"></Setter> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="{StaticResource ItemMouseOverBackground}"></Setter> <Setter Property="Foreground" Value="{StaticResource ItemMouseOverForeground}"></Setter> </Trigger> <!-- 不在当月的日期 --> <Trigger Property="IsInactive" Value="True"> <Setter Property="Opacity" Value="0.8" TargetName="Grid"></Setter> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter Property="Opacity" Value="{StaticResource DisableOpacity}" TargetName="Grid"></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
最后综合以上的样式, 定义我们需要的 Calendar 样式就差一步之遥了.
<!-- 默认日历样式 --> <Style x:Key="DefaultCalendar" TargetType="{x:Type Calendar}"> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="Foreground" Value="{StaticResource TextForeground}" /> <Setter Property="CalendarDayButtonStyle" Value="{StaticResource CalendarDayButtonStyle}" /> <Setter Property="CalendarItemStyle" Value="{StaticResource CalendarItemStyle}" /> <Setter Property="CalendarButtonStyle" Value="{StaticResource CalendarButtonStyle}" /> <Setter Property="Background" Value="{StaticResource PopupBackground}" /> <Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="FontSize" Value="13" /> <Setter Property="FontFamily" Value="{StaticResource FontFamily}" /> <Setter Property="IsTodayHighlighted" Value="True" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Calendar}"> <StackPanel x:Name="PART_Root" HorizontalAlignment="Center" Background="Transparent"> <CalendarItem x:Name="PART_CalendarItem" BorderBrush="{TemplateBinding BorderBrush}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Style="{TemplateBinding CalendarItemStyle}" /> </StackPanel> </ControlTemplate> </Setter.Value> </Setter> </Style>
三.DatePicker 自定义样式, 及 Label 标签, 水印, 清除日期功能扩展
有了上面的日历样式, 下面做 DatePicker 的样式就好办了, 其实就是 TextBox+Button+Calendar. 此处的实现同上一篇 (WPF 自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox 样式) 思路基本一致, 因此本文就不做更多的解释, 可以参考本系列前面的文章 (末尾附录有链接) 先看看效果图:
3.1 DatePicker 自定义样式
基本样式定义:
View Code
水印效果:
使用示例:
<DatePicker Margin="3" core:ControlAttachProperty.Watermark="妈的快输入日期"/> <DatePicker Margin="3" SelectedDate="{x:Static system:DateTime.Today}"/> <DatePicker Margin="3" IsEnabled="False" SelectedDate="{x:Static system:DateTime.Today}"/>
3.2 Label 标签
通过扩展基础样式中的标签附加属性实现, 定义样式代码:
<!--DatePicker 包含附加属性 Label 的样式 LabelDatePicker --> <Style TargetType="{x:Type DatePicker}" x:Key="LabelDatePicker" BasedOn="{StaticResource DefaultDatePicker}"> <Setter Property="Width" Value="260"></Setter> <Setter Property="local:ControlAttachProperty.LabelTemplate"> <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Border Width="60" Background="{StaticResource TextLabelBackground}"> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Text="{TemplateBinding Content}"></TextBlock> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
效果图:
使用示例:
<DatePicker Margin="3" Style="{StaticResource LabelClearButtonDatePicker}" core:ControlAttachProperty.Watermark="选择出生日期" core:ControlAttachProperty.Label="出生日期" /> <DatePicker Margin="3" Style="{StaticResource LabelDatePicker}" core:ControlAttachProperty.Label="死亡日期" SelectedDate="{x:Static system:DateTime.Today}" /> <DatePicker Margin="3" Style="{StaticResource LabelDatePicker}" core:ControlAttachProperty.Label="非法日期" IsEnabled="False" SelectedDate="{x:Static system:DateTime.Today}" />
3.3 清除日期值的功能扩展
此功能在前面的文章有介绍过(参考本文末尾链接), 效果在上面的图片中可以看到. 样式代码:
<!--DatePicker 包含清除 Text 按钮的样式 ClearButtonDatePicker --> <Style TargetType="{x:Type DatePicker}" x:Key="ClearButtonDatePicker" BasedOn="{StaticResource DefaultDatePicker}"> <Setter Property="local:ControlAttachProperty.AttachContent"> <Setter.Value> <ControlTemplate> <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0" local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type DatePicker}}}" Margin="1,3,0,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--DatePicker 包含附加属性 Label, 以及 ClearText 按钮的样式 LabelClearButtonDatePicker --> <Style TargetType="{x:Type DatePicker}" x:Key="LabelClearButtonDatePicker" BasedOn="{StaticResource DefaultDatePicker}"> <Setter Property="Width" Value="280"></Setter> <Setter Property="local:ControlAttachProperty.LabelTemplate"> <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Border Width="60" Background="{StaticResource TextLabelBackground}"> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2" Text="{TemplateBinding Content}"></TextBlock> </Border> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="local:ControlAttachProperty.AttachContent"> <Setter.Value> <ControlTemplate> <local:FButton FIcon="" Style="{StaticResource FButton_Transparency}" IsTabStop="False" FIconMargin="0" local:ControlAttachProperty.IsClearTextButtonBehaviorEnabled="True" Command="local:ControlAttachProperty.ClearTextCommand" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type DatePicker}}}" Margin="0,3,0,4" FIconSize="14" Foreground="{StaticResource TextForeground}" Cursor="Arrow"/> </ControlTemplate> </Setter.Value> </Setter> </Style>
使用示例:
<DatePicker Margin="3" Style="{StaticResource ClearButtonDatePicker}" /> <DatePicker Margin="3" Style="{StaticResource LabelClearButtonDatePicker}" core:ControlAttachProperty.Watermark="选择出生日期" core:ControlAttachProperty.Label="出生日期" />
附录: 参考引用
WPF 自定义控件与样式(1)- 矢量字体图标(iconfont) https://www.cnblogs.com/anding/p/4961215.html
WPF 自定义控件与样式(2)- 自定义按钮 FButton https://www.cnblogs.com/anding/p/4968050.html
WPF 自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox 样式, 水印, Label 标签, 功能扩展 https://www.cnblogs.com/anding/p/4970845.html
WPF 自定义控件与样式(4)-CheckBox/RadioButton 自定义样式 https://www.cnblogs.com/anding/p/4976559.html
来源: http://www.bubuko.com/infodetail-3356090.html