通过Silverlight中Calendar控件的扩展学习XAML(下)


CalendarDayButtonStyle:

<Style x:Key="CalendarDayButtonStyle1"
	   TargetType="System_Windows_Controls_Primitives:CalendarDayButton">
	<Setter Property="Background"
			Value="#FFBADDE9" />
	<Setter Property="FontSize"
			Value="10" />
	<Setter Property="HorizontalContentAlignment"
			Value="Center" />
	<Setter Property="VerticalContentAlignment"
			Value="Center" />
	<Setter Property="MinWidth"
			Value="5" />
	<Setter Property="MinHeight"
			Value="5" />
	<Setter Property="Template">
		<Setter.Value>
			<ControlTemplate TargetType="System_Windows_Controls_Primitives:CalendarDayButton">
				<Grid>
					<VisualStateManager.VisualStateGroups>
						<VisualStateGroup x:Name="CommonStates">
							<VisualStateGroup.Transitions>
								<VisualTransition GeneratedDuration="0:0:0.1" />
							</VisualStateGroup.Transitions>
							<VisualState x:Name="Normal" />
							<VisualState x:Name="MouseOver">
								<Storyboard>
									<DoubleAnimation Duration="0"
													 To=".5"
													 Storyboard.TargetProperty="Opacity"
													 Storyboard.TargetName="Background" />
								</Storyboard>
							</VisualState>
							<VisualState x:Name="Pressed">
								<Storyboard>
									<DoubleAnimation Duration="0"
													 To=".5"
													 Storyboard.TargetProperty="Opacity"
													 Storyboard.TargetName="Background" />
								</Storyboard>
							</VisualState>
							<VisualState x:Name="Disabled">
								<Storyboard>
									<DoubleAnimation Duration="0"
													 To="0"
													 Storyboard.TargetProperty="Opacity"
													 Storyboard.TargetName="Background" />
									<DoubleAnimation Duration="0"
													 To=".35"
													 Storyboard.TargetProperty="Opacity"
													 Storyboard.TargetName="Content" />
								</Storyboard>
							</VisualState>
						</VisualStateGroup>
						<VisualStateGroup x:Name="SelectionStates">
							<VisualStateGroup.Transitions>
								<VisualTransition GeneratedDuration="0" />
							</VisualStateGroup.Transitions>
							<VisualState x:Name="Unselected" />
							<VisualState x:Name="Selected">
								<Storyboard>
									<DoubleAnimation Duration="0"
													 To=".75"
													 Storyboard.TargetProperty="Opacity"
													 Storyboard.TargetName="SelectedBackground" />
								</Storyboard>
							</VisualState>
						</VisualStateGroup>
						<VisualStateGroup x:Name="CalendarButtonFocusStates">
							<VisualStateGroup.Transitions>
								<VisualTransition GeneratedDuration="0" />
							</VisualStateGroup.Transitions>
							<VisualState x:Name="CalendarButtonFocused">
								<Storyboard>
									<ObjectAnimationUsingKeyFrames Duration="0"
																   Storyboard.TargetProperty="Visibility"
																   Storyboard.TargetName="FocusVisual">
										<DiscreteObjectKeyFrame KeyTime="0"
																Value="Visible" />
									</ObjectAnimationUsingKeyFrames>
								</Storyboard>
							</VisualState>
							<VisualState x:Name="CalendarButtonUnfocused">
								<Storyboard>
									<ObjectAnimationUsingKeyFrames Duration="0"
																   Storyboard.TargetProperty="Visibility"
																   Storyboard.TargetName="FocusVisual">
										<DiscreteObjectKeyFrame KeyTime="0"
																Value="Collapsed" />
									</ObjectAnimationUsingKeyFrames>
								</Storyboard>
							</VisualState>
						</VisualStateGroup>
						<VisualStateGroup x:Name="ActiveStates">
							<VisualStateGroup.Transitions>
								<VisualTransition GeneratedDuration="0" />
							</VisualStateGroup.Transitions>
							<VisualState x:Name="Active" />
							<VisualState x:Name="Inactive">
								<Storyboard>
									<ColorAnimation Duration="0"
													To="#FF777777"
													Storyboard.TargetProperty="(ContentControl.Foreground).(GradientBrush.GradientStops)[2].(GradientStop.Color)"
													Storyboard.TargetName="Content" />
									<ColorAnimation Duration="0"
													To="#FF777777"
													Storyboard.TargetProperty="(ContentControl.Foreground).(GradientBrush.GradientStops)[3].(GradientStop.Color)"
													Storyboard.TargetName="Content" />
								</Storyboard>
							</VisualState>
						</VisualStateGroup>
						<VisualStateGroup x:Name="DayStates">
							<VisualStateGroup.Transitions>
								<VisualTransition GeneratedDuration="0" />
							</VisualStateGroup.Transitions>
							<VisualState x:Name="RegularDay" />
							<VisualState x:Name="Today">
								<Storyboard>
									<DoubleAnimation Duration="0"
													 To="1"
													 Storyboard.TargetProperty="Opacity"
													 Storyboard.TargetName="TodayBackground" />
									<DoubleAnimation Duration="0"
													 To="1"
													 Storyboard.TargetProperty="(ContentControl.Foreground).(GradientBrush.GradientStops)[1].(GradientStop.Offset)"
													 Storyboard.TargetName="Content" />
									<DoubleAnimation Duration="0"
													 To="1"
													 Storyboard.TargetProperty="(ContentControl.Foreground).(GradientBrush.GradientStops)[2].(GradientStop.Offset)"
													 Storyboard.TargetName="Content" />
								</Storyboard>
							</VisualState>
						</VisualStateGroup>
						<VisualStateGroup x:Name="BlackoutDayStates">
							<VisualStateGroup.Transitions>
								<VisualTransition GeneratedDuration="0" />
							</VisualStateGroup.Transitions>
							<VisualState x:Name="NormalDay" />
							<VisualState x:Name="BlackoutDay">
								<Storyboard>
									<DoubleAnimation Duration="0"
													 To=".2"
													 Storyboard.TargetProperty="Opacity"
													 Storyboard.TargetName="BlackoutVisual" />
								</Storyboard>
							</VisualState>
						</VisualStateGroup>
					</VisualStateManager.VisualStateGroups>
					<Rectangle x:Name="TodayBackground"
							   Fill="#FFAAAAAA"
							   Opacity="0"
							   RadiusY="1"
							   RadiusX="1" />
					<Rectangle x:Name="SelectedBackground"
							   Fill="{TemplateBinding Background}"
							   Opacity="0"
							   RadiusY="1"
							   RadiusX="1" />
					<Rectangle x:Name="Background"
							   Fill="{TemplateBinding Background}"
							   Opacity="0"
							   RadiusY="1"
							   RadiusX="1" />
					<ContentControl x:Name="Content"
									ContentTemplate="{TemplateBinding ContentTemplate}"
									Content="{TemplateBinding Content}"
									FontSize="{TemplateBinding FontSize}"
									HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
									IsTabStop="False"
									Margin="5,1,5,1"
									VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
									Style="{StaticResource ContentControlStyle1}">
						<ContentControl.Foreground>
							<LinearGradientBrush>
								<GradientStop Color="#FFFFFFFF"
											  Offset="0" />
								<GradientStop Color="#FFFFFFFF"
											  Offset="0" />
								<GradientStop Color="#FF333333"
											  Offset="0" />
								<GradientStop Color="#FF333333"
											  Offset="1" />
							</LinearGradientBrush>
						</ContentControl.Foreground>
					</ContentControl>
					<Path x:Name="BlackoutVisual"
						  Data="M8.1772461,11.029181 L10.433105,11.029181 L11.700684,12.801641 L12.973633,11.029181 L15.191895,11.029181 L12.844727,13.999395 L15.21875,17.060919 L12.962891,17.060919 L11.673828,15.256231 L10.352539,17.060919 L8.1396484,17.060919 L10.519043,14.042364 z"
						  Fill="#FF000000"
						  HorizontalAlignment="Stretch"
						  Margin="3"
						  Opacity="0"
						  RenderTransformOrigin="0.5,0.5"
						  Stretch="Fill"
						  VerticalAlignment="Stretch" />
					<Rectangle x:Name="FocusVisual"
							   IsHitTestVisible="false"
							   RadiusY="1"
							   RadiusX="1"
							   Stroke="#FF6DBDD1"
							   Visibility="Collapsed" />
				</Grid>
			</ControlTemplate>
		</Setter.Value>
	</Setter>
</Style>


这次先看看折叠版:

只有ContentControl是需要关注的核心,再看下Blend中的视图



注意到content的datacontext属性,不再是集成的Calendar,而是DateTime!也就是每一格的日期!而且至今我仍未有找到这个格子可绑定Observable<>属性的Source。

因为格子里既有原生的日期,也有需要自定义的部分,所以我们将Content用另一个模板加载:

<Style x:Key="ContentControlStyle1"
	   TargetType="ContentControl">
	<Setter Property="Foreground" Value="#FF000000" />
	<Setter Property="HorizontalContentAlignment" Value="Left" />
	<Setter Property="VerticalContentAlignment" Value="Top" />
	<Setter Property="Template">
		<Setter.Value>
			<ControlTemplate TargetType="ContentControl">
				<Grid>
					<Grid.RowDefinitions>
						<RowDefinition Height="Auto"></RowDefinition>
						<RowDefinition Height="*"></RowDefinition>
					</Grid.RowDefinitions>
					<ContentPresenter Cursor="{TemplateBinding Cursor}" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
						<TextBlock FontFamily="Georgia"
								   FontSize="15"
								   Text="{TemplateBinding Content}"></TextBlock>
					</ContentPresenter>
					<TextBlock Grid.Row="1"
							   FontSize="8.5"
							   Foreground="#aa161616">
					<TextBlock.Text>
						<Binding Converter="{StaticResource LunaDateConverter}"/>
					</TextBlock.Text>
					</TextBlock>
				</Grid>
			</ControlTemplate>
		</Setter.Value>
	</Setter>
</Style>


这个模板定义了content的样式,同时,利用一个ValueConverter实现了公历日期(DataContext)向农历日期的转换。


本来这样也就OK了,可用ValueConverter的时候只有一个日期参数,有时我们需要相同的日期显示不同的内容,例如不同的班组会有不同的班次安排等。

自然的,一开始便想用ConverterParameter将ViewModel实例作为参数传进去,例如:

<TextBlock Grid.Row="1"
           FontSize="8.5"
           Text='{Binding Converter={StaticResource DateToShiftContentConverter},ConverterParameter={Binding DataContext}, Mode=OneWay}'
           Foreground="#aa161616"/>



但正如我之前所言,DayButton的Content绑定的DataContext不再是继承于Calendar,而是当前格子的日期,因此此处的Binding是找不到通向ViewModel的路径的。后来我想用TemplateBinding尝试将ViewModel从父级一层层传下来(如利用Tag属性)但还是无法找到父级,获取到的一直是null,终究作罢:

<TextBlock Grid.Row="1"
	FontSize="8.5"
	Text='{Binding Converter={StaticResource DateToShiftContentConverter},ConverterParameter={TemplateBinding Tag}, Mode=OneWay}'
	Foreground="#aa161616"/>



期间我在网上各种查资料,试图设法将属性绑定到DayButton上,比如Josh Smith的 Attaching a Virtual Branch to the Logical Tree in WPF 就是一种通过所谓“逻辑树虚拟枝”技术将ViewModel间接保存下来供任意内容读取。但实现有点略复杂,试了试也没调好,遂作罢,但这篇文章给了我很好的思路。

最后,我通过ValueConverter的声明想到,可以尝试通过一个中间的静态资源实现ViewModel的传递:

<UserControl.Resources>
    <ViewModelConverter:DateToShiftContentConverter x:Key='DateToShiftContentConverter' />
    <ViewModel:CalendarMonthViewModel x:Key='CalendarMonthViewModel' />
    ......
</UserControl.Resources>

<UserControl.DataContext>
   <Binding  Source='{StaticResource CalendarMonthViewModel}' />
</UserControl.DataContext>
<TextBlock Grid.Row="1"
    FontSize="8.5"
    Foreground="#aa161616"
    Text='{Binding Converter={StaticResource DateToShiftContentConverter},ConverterParameter={StaticResource CalendarMonthViewModel}, Mode=OneWay}'
    FontFamily="Microsoft YaHei" />


如此,就完美解决的参数的传递问题。





在对Calendar个性化设置的路上,虽然走了不少弯路,但最终实现了功能的同时,自己对Xaml和Wpf的一些特性有了更深入的了解和学习。







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值