控件模板学习笔记(三)
根据前两个博客的学习,已经可以构造简单的控件模板。这篇博客就试着构造一个稍微负载的控件模板。PS:这个控件模板示例包括在《WPF编程宝典》这本书里,如果小伙伴们
觉得我说的不是太明确,可以在书里自行查看
在前面的博客中提到一个新的控件模板会替换掉控件原有的控件模板,所以就需要确保新模板能够满足控件的实现代码的需要。现在就试着为ListBox这个控件定义一个模板,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<Style TargetType="{x:Type ListBox}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBox}"> <Border Name="Border" Background="LightGray" BorderBrush="Gray" BorderThickness="1" CornerRadius="3"> <ScrollViewer Focusable="True"> <ItemsPresenter Margin="2"></ItemsPresenter> </ScrollViewer> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
当定义完这个样式后会发现,当选择玄素总是使用熟悉的蓝色背景。为了改变这个行为,需要为ListBoxItem控件添加控件模板,因为ListBoxItem是内容控件,所以需要使用ContentPresenter元素在其内部放置项的内容。除这些基本内容外,还有当鼠标移到项上或单机时做出相应。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<Style TargetType="{x:Type ListBoxItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBoxItem}"> <Border Name="Border"> <ContentPresenter /> </Border> <ControlTemplate.Triggers> <EventTrigger RoutedEvent="ListBoxItem.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="FontSize" To="20" Duration="0:0:1"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent="ListBoxItem.MouseLeave"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="FontSize" BeginTime="0:0:0.5" Duration="0:0:0.2"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
使用这个模板创建当将鼠标移动到当前定位的项上时使用动画放大项,当鼠标离开时是回复项。所以当鼠标移动较快时,就会出现“鱼眼”效果。
可以根据笔记一中分析控件看出ListBox有一个重要部分是ScrollViewer,其中ScrollBar是ScrollViewer的一部分,下面就改变ScrollBar的模板。
ScrollBar控件有点复杂,它是由更小的部分组成的集合,
滚动条的背景是由Track类表示。滚动条的首尾出是按钮,通过这些按钮可以向上或向下(向左或向右)滚动一个步长。RepeatButton和Button的重要区别在于,如果在RepeatButton按钮上保持鼠标为按下状态,就会反复出发Click事件。在滚动条中间的是Thumb元素。滑块两侧的空白是另外两个RepeatButton对象构成,当单击这两个按钮的任何一个,滚动条就会滚动一整页(一页是滚动内容所在的可视窗口中的内部容量)。下面是滚动条的模板
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="18" /> <RowDefinition Height="*" /> <RowDefinition Height="18" /> </Grid.RowDefinitions> <RepeatButton Grid.Row="0" Height="18" Style="{StaticResource ScrollBarLineButtonStyle}" Command="ScrollBar.LineUpCommand"> <Path Fill="{StaticResource GlyphBrush}" Data="M 0 4 L 8 4 L 4 0 Z"></Path> </RepeatButton> <Track Name="PART_Track" Grid.Row="1" IsDirectionReversed="True" ViewportSize="0"> <Track.DecreaseRepeatButton> <RepeatButton Command="ScrollBar.PageUpCommand" Style="{StaticResource ScrollBarPageButtonStyle}"> </RepeatButton> </Track.DecreaseRepeatButton> <Track.Thumb> <Thumb Style="{StaticResource ScrollBarThumbStyle}"></Thumb> </Track.Thumb> <Track.IncreaseRepeatButton> <RepeatButton Command="ScrollBar.PageDownCommand" Style="{StaticResource ScrollBarPageButtonStyle}"></RepeatButton> </Track.IncreaseRepeatButton> </Track> <RepeatButton Grid.Row="2" Height="18" Style="{StaticResource ScrollBarLineButtonStyle}" Command="ScrollBar.LineDownCommand"> <Path Fill="{StaticResource GlyphBrush}" Data="M 0 0 L 4 4 L 8 0 Z" /> </RepeatButton> </Grid> </ControlTemplate>
属性ViewportSize属性设为0,可确保Thumb总有相同的尺寸
其中ScrollBarLineButtonStyle定义滚动条首尾的RepeatButton的样式,显示为椭圆形,内容为正反三角形,样式定义如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<Style x:Key="ScrollBarLineButtonStyle" TargetType="{x:Type RepeatButton}"> <Setter Property="Focusable" Value="False" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RepeatButton}"> <Grid Margin="1"> <Ellipse Name="Border" StrokeThickness="1" Stroke="{StaticResource StandardBorderBrush}" Fill="{StaticResource StandardBrush}"></Ellipse> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
其中Focusable为False意思为不能获取焦点。
ScrollBarPageButtonStyle定义Thumb中的RepeatButton(就是空白处)为透明,样式如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<Style x:Key="ScrollBarPageButtonStyle" TargetType="{x:Type RepeatButton}"> <Setter Property="IsTabStop" Value="False" /> <Setter Property="Focusable" Value="False" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RepeatButton}"> <Border Background="Transparent" /> </ControlTemplate> </Setter.Value> </Setter> </Style>
ScrollBarThumbStyle定义Thumb显示为蓝色的椭圆形,样式定义如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<Style x:Key="ScrollBarThumbStyle" TargetType="{x:Type Thumb}"> <Setter Property="IsTabStop" Value="False" /> <Setter Property="Focusable" Value="False" /> <Setter Property="Margin" Value="1,0,1,0" /> <Setter Property="Background" Value="{StaticResource StandardBrush}" /> <Setter Property="BorderBrush" Value="{StaticResource StandardBorderBrush}" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Thumb}"> <Ellipse Stroke="{StaticResource StandardBorderBrush}" Fill="{StaticResource StandardBorderBrush}" /> </ControlTemplate> </Setter.Value> </Setter> </Style>
其中属性IsTabStop为False意思是Thumb不包括在导航选项上
最后设置竖型滚动条的样式
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<Style TargetType="{x:Type ScrollBar}"> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="OverridesDefaultStyle" Value="True" /> <Style.Triggers> <Trigger Property="Orientation" Value="Vertical"> <Setter Property="Width" Value="18" /> <Setter Property="Height" Value="Auto" /> <Setter Property="Template" Value="{StaticResource VerticalScrollBar}" /> </Trigger> </Style.Triggers> </Style>
为什么在Triger里面设置Template,因为此样式只适用于竖型滚动条样式。以确保滚动条(水平型)不会自动应用该样式,却又不影响竖型滚动条自动应用该样式
最后效果图如下
因为这个例子是书中的,所以举一反三,下一个博客我会自定义一个新的控件模板来应用于一个稍微复杂一点的控件