本文通过自定义calendar的开发,通过分析Silverlight自带的Calendar的样式、模板的分析,实现日历的定制化开发。
WPF中,自带的Calendar控件是这样子的:
而我们想要的结果是这样子的:
这个控件有两种方法去做。
一个是自己重新绘制图形,用一个7*6的表格来放日期,再根据当前月第一天的星期,计算出第一行第一列的日期,然后依次填充即可。详情可参考 Kelly Elias的这篇文章An Editable WPF Calendar Control,但这个控件其中用到了很重要的一个类UniformGrID在Silverlight中是没有的,需要自己重写,不要急,Jeff Wilco在博文UniformGrid for Silverlight中提供了解决方案。
另一个则是基于自带的Calendar,利用XAML强大的样式(Style)和模板(Template)功能完成扩展,也就是今天要讲的。
第一种方式实现简单容易扩展,可快速满足各种需求。但是功能太少,一些基本的日历功能都需要重写,比如月份更换、日期选择和反选等等。相反,第二种因为是基于自带的Calendar,不用引用过多的外部资源,即可拥有许多强大的功能,还能和其他控件融为一体等等。所以不用说,肯定用第二种的好。
关于Calendar的样式和模板,MSDN给了完整的示例。本文也是基于官方示例和非官方英文文献撰写。
首先,创建一个控件,添加一个UserControl:
<GrID x:name="LayoutRoot" Background="White"> <VIEwBox> <sdk:Calendar name='calendar1' /> </VIEwBox> </GrID>其中,VIEwBox是用来实现Calendar自适应大小的。
一个Calendar可设置的样式包括Style、CalendarItemStyle、CalendarbuttonStyle和CalendarDaybuttonStyle
Style是用来设置Calendar整体的样式:
<Style x:Key="CalendarStyle1" targettype="sdk:Calendar"> <Setter Property="IsTabStop" Value="False" /> <Setter Property="Background"> <Setter.Value> <linearGradIEntBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradIEntStop color="#FFD3DEE8" Offset="0" /> <GradIEntStop color="#FFD3DEE8" Offset="0.16" /> <GradIEntStop color="#FFFCFCFD" Offset="0.16" /> <GradIEntStop color="#FFFFFFFF" Offset="1" /> </linearGradIEntBrush> </Setter.Value> </Setter>-------------------------------------------------------------------------------------------------------------------------- <Setter Property="Template"> <Setter.Value> <ControlTemplate targettype="sdk:Calendar"> <GrID x:name="Root" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <System_windows_Controls_Primitives:CalendarItem VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" x:name="CalendarItem" borderBrush="{TemplateBinding borderBrush}" borderThickness="{TemplateBinding borderThickness}" Background="{TemplateBinding Background}" Style="{StaticResource CalendarItemStyle1}" /> </GrID> </ControlTemplate> </Setter.Value> -------------------------------------------------------------------------------------------------------------------------- </Setter> </Style>
CalendarItemStyle是用来设置CalendarItem(即月份选择部分和日期排列),CalendarItem的设置也可以嵌套到Style中设置(Style代码中横线夹住部分)
<Style x:Key="CalendarItemStyle1" targettype="System_windows_Controls_Primitives:CalendarItem"> <Setter Property='VerticalAlignment'Value='Stretch' /> <Setter Property='VerticalContentAlignment' Value='Stretch' /> <Setter Property='HorizontalAlignment' Value='Stretch' /> <Setter Property='HorizontalContentAlignment' Value='Stretch' /> <Setter Property="Template"> <Setter.Value> <ControlTemplate targettype="System_windows_Controls_Primitives:CalendarItem"> <GrID HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <GrID.Resources> <SolIDcolorBrush x:Key="DisabledBrush" color="#8CFFFFFF" /> </GrID.Resources> <visualstatemanager.VisualStateGroups> <VisualStateGroup x:name="CommonStates"> <VisualState x:name="normal" /> <VisualState x:name="Disabled"> <Storyboard> <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.Targetname="DisabledVisual" /> </Storyboard> </VisualState> </VisualStateGroup> </visualstatemanager.VisualStateGroups> <border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" borderBrush="{TemplateBinding borderBrush}" borderThickness="{TemplateBinding borderThickness}" Background="{TemplateBinding Background}" CornerRadius="5" margin="2"> <border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" borderBrush="#FFFFFFFF" borderThickness="2" CornerRadius="5" padding="5"> <GrID HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <GrID.Resources> <ControlTemplate x:Key="headerbuttonTemplate" targettype="button"> <GrID Cursor="Hand"> <visualstatemanager.VisualStateGroups> <VisualStateGroup x:name="CommonStates"> <VisualState x:name="normal" /> <VisualState x:name="MouSEOver"> <Storyboard> <colorAnimation Duration="0" To="#FF73A9D8" Storyboard.TargetProperty="(ContentControl.Foreground).(SolIDcolorBrush.color)" Storyboard.Targetname="Content" /> </Storyboard> </VisualState> <VisualState x:name="Disabled"> <Storyboard> <DoubleAnimation Duration="0" To=".5" Storyboard.TargetProperty="Opacity" Storyboard.Targetname="Content" /> </Storyboard> </VisualState> </VisualStateGroup> </visualstatemanager.VisualStateGroups> <ContentControl x:name="Content" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="#FF333333" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsTabStop="False" margin="1,5,1,9" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> </GrID> </ControlTemplate> <DataTemplate x:name="DayTitleTemplate"> <TextBlock FontWeight="Bold" margin="5" FontSize="12" HorizontalAlignment="left" Text="{Binding}" VerticalAlignment="Center"></TextBlock> </DataTemplate> <ControlTemplate x:Key="PrevIoUsbuttonTemplate" targettype="button"> <GrID Cursor="Hand"> <visualstatemanager.VisualStateGroups> <VisualStateGroup x:name="CommonStates"> <VisualState x:name="normal" /> <VisualState x:name="MouSEOver"> <Storyboard> <colorAnimation Duration="0" To="#FF73A9D8" Storyboard.TargetProperty="(Path.Fill).(SolIDcolorBrush.color)" Storyboard.Targetname="IconPath" /> </Storyboard> </VisualState> <VisualState x:name="Disabled"> <Storyboard> <DoubleAnimation Duration="0" To=".5" Storyboard.TargetProperty="(Path.Fill).(SolIDcolorBrush.Opacity)" Storyboard.Targetname="IconPath" /> </Storyboard> </VisualState> </VisualStateGroup> </visualstatemanager.VisualStateGroups> <Rectangle Fill="#11E5EBF1" Opacity="1" Stretch="Fill" /> <GrID> <Path x:name="IconPath" Data="M288.75,232.25 L288.75,240.625 L283,236.625 z" Fill="#FF333333" HorizontalAlignment="left" Height="10" margin="14,-6,0" Stretch="Fill" VerticalAlignment="Center" WIDth="6" /> </GrID> </GrID> </ControlTemplate> <ControlTemplate x:Key="NextbuttonTemplate" targettype="button"> <GrID Cursor="Hand"> <visualstatemanager.VisualStateGroups> <VisualStateGroup x:name="CommonStates"> <VisualState x:name="normal" /> <VisualState x:name="MouSEOver"> <Storyboard> <colorAnimation Duration="0" To="#FF73A9D8" Storyboard.TargetProperty="(Path.Fill).(SolIDcolorBrush.color)" Storyboard.Targetname="IconPath" /> </Storyboard> </VisualState> <VisualState x:name="Disabled"> <Storyboard> <DoubleAnimation Duration="0"To=".5" Storyboard.TargetProperty="(Path.Fill).(SolIDcolorBrush.Opacity)" Storyboard.Targetname="IconPath" /> </Storyboard> </VisualState> </VisualStateGroup> </visualstatemanager.VisualStateGroups> <Rectangle Fill="#11E5EBF1" Opacity="1" Stretch="Fill" /> <GrID> <Path x:name="IconPath" Data="M282.875,231.875 L282.875,240.375 L288.625,236 z" Fill="#FF333333" HorizontalAlignment="Right" Height="10" margin="0,14,0" Stretch="Fill" VerticalAlignment="Center" WIDth="6" /> </GrID> </GrID> </ControlTemplate> </GrID.Resources> <GrID.ColumnDeFinitions> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> </GrID.ColumnDeFinitions> <GrID.RowDeFinitions> <RowDeFinition Height="auto" /> <RowDeFinition Height="*" /> </GrID.RowDeFinitions> <button x:name="PrevIoUsbutton" HorizontalAlignment="left" Height="20" Template="{StaticResource PrevIoUsbuttonTemplate}" Visibility="Collapsed" WIDth="28" /> <button x:name="headerbutton" GrID.Column="1" FontWeight="Bold" FontSize="10.5" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" Template="{StaticResource buttonControlTemplate1}" VerticalAlignment="Center" /> <button x:name="Nextbutton" GrID.Column="2" HorizontalAlignment="Right" Height="20" Template="{StaticResource NextbuttonTemplate}" Visibility="Collapsed" WIDth="28" /> <GrID x:name="MonthVIEw" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" GrID.ColumnSpan="3" GrID.Row="1" Visibility="Collapsed"> <GrID.ColumnDeFinitions> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> </GrID.ColumnDeFinitions> <GrID.RowDeFinitions> <RowDeFinition Height="auto" /> <RowDeFinition Height="auto" /> <RowDeFinition Height="auto" /> <RowDeFinition Height="auto" /> <RowDeFinition Height="auto" /> <RowDeFinition Height="auto" /> <RowDeFinition Height="auto" /> </GrID.RowDeFinitions> </GrID> <GrID x:name="YearVIEw" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" GrID.ColumnSpan="3" GrID.Row="1" Visibility="Collapsed"> <GrID.ColumnDeFinitions> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> <ColumnDeFinition WIDth="auto" /> </GrID.ColumnDeFinitions> <GrID.RowDeFinitions> <RowDeFinition Height="auto" /> <RowDeFinition Height="auto" /> <RowDeFinition Height="auto" /> </GrID.RowDeFinitions> </GrID> </GrID> </border> </border> <Rectangle x:name="DisabledVisual" Fill="{StaticResource DisabledBrush}" margin="0,2,2" Opacity="0" RadiusY="2" RadiusX="2" Stretch="Fill" stroke="{StaticResource DisabledBrush}" strokeThickness="1" Visibility="Collapsed" /> </GrID> </ControlTemplate> </Setter.Value> </Setter> </Style>
我们分析一下这个长长的XAML,Blend是分析样式和模板的一个非常好用的工具,在Blend中编辑该模板:
右边列出那长串XAML所包含的树形结构,折叠后的XAML即:
PrevIoUsbuttonTemplate定义了“上一个月”按钮的样式,Nextbutton指定是“下一个月”按钮,而headerbutton就是“月份”以及“日历名称”的部分。至于后面的MonthVIEw和YearVIEw,则分别定义了正常和点击当前月份后日历的显示。
在这里说一下,CalendarItem是在Calendar逻辑树下的,所以Calendar的DataContext是可以被CalendarItem获取到的,所以,在设置Calendar的各个button时候,是可以绑定viewmodel(MVVM模式中VM概念)中的属性的。例如:
<ControlTemplate x:Key="buttonControlTemplate" targettype="button"> <GrID Cursor="Hand"> <GrID.RowDeFinitions> <RowDeFinition></RowDeFinition> <RowDeFinition></RowDeFinition> </GrID.RowDeFinitions> <ContentControl x:name="Content" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="#FF333333" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsTabStop="False" margin="1,9" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> <TextBlock Foreground="#ff666666" FontSize="9" margin="-20" GrID.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Text='{Binding CalendarModel.Resourcename}' /> </GrID> </ControlTemplate>其中,Text='{Binding CalendarModel.Calendarname}'是可以找到UserControl.DataContext绑定的Calendarviewmodel实例的。所以,通过这个button模板,可以轻易动态修改日历名称。
下节中,本文将继续讨论CalendarDaybuttonStyle的设置以及Daybutton内容的绑定和设置
总结以上是内存溢出为你收集整理的通过Silverlight中Calendar控件的扩展学习XAML(上)全部内容,希望文章能够帮你解决通过Silverlight中Calendar控件的扩展学习XAML(上)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)