微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

通过Silverlight中Calendar控件的扩展学习XAML上

本文通过自定义calendar的开发,通过分析Silverlight自带的Calendar的样式、模板的分析,实现日历的定制化开发。


WPF中,自带的Calendar控件是这样子的:

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.ColumnDe@R_502_4327@ns>
                                            <ColumnDe@R_502_4327@n Width="Auto" />
                                            <ColumnDe@R_502_4327@n Width="Auto" />
                                            <ColumnDe@R_502_4327@n Width="Auto" />
                                        </Grid.ColumnDe@R_502_4327@ns>
                                        <Grid.RowDe@R_502_4327@ns>
                                            <RowDe@R_502_4327@n Height="Auto" />
                                            <RowDe@R_502_4327@n Height="*" />
                                        </Grid.RowDe@R_502_4327@ns>
                                        <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.ColumnDe@R_502_4327@ns>
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                            </Grid.ColumnDe@R_502_4327@ns>
                                            <Grid.RowDe@R_502_4327@ns>
                                                <RowDe@R_502_4327@n Height="Auto" />
                                                <RowDe@R_502_4327@n Height="Auto" />
                                                <RowDe@R_502_4327@n Height="Auto" />
                                                <RowDe@R_502_4327@n Height="Auto" />
                                                <RowDe@R_502_4327@n Height="Auto" />
                                                <RowDe@R_502_4327@n Height="Auto" />
                                                <RowDe@R_502_4327@n Height="Auto" />
                                            </Grid.RowDe@R_502_4327@ns>
                                        </Grid>
                                        <Grid x:Name="YearView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.ColumnSpan="3" Grid.Row="1" Visibility="Collapsed">
                                            <Grid.ColumnDe@R_502_4327@ns>
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                                <ColumnDe@R_502_4327@n Width="Auto" />
                                            </Grid.ColumnDe@R_502_4327@ns>
                                            <Grid.RowDe@R_502_4327@ns>
                                                <RowDe@R_502_4327@n Height="Auto" />
                                                <RowDe@R_502_4327@n Height="Auto" />
                                                <RowDe@R_502_4327@n Height="Auto" />
                                            </Grid.RowDe@R_502_4327@ns>
                                        </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.RowDe@R_502_4327@ns>
                    <RowDe@R_502_4327@n></RowDe@R_502_4327@n>
                    <RowDe@R_502_4327@n></RowDe@R_502_4327@n>
                </Grid.RowDe@R_502_4327@ns>
                <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内容的绑定和设置

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐