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

通过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的一些特性有了更深入的了解和学习。

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

相关推荐