文章目录
前言
滚动条是一个常见控件,很多控件中都包含滚动条,比如ListBox、ComboBox、GridView等。wpf默认的滚动条的样式并不是特别好看,而且经常与UI设计的滚动条不一致,这个时候我们就需要自定义滚动条了。值得一提的是这,wpf的滚动条定制性和拓展性都非常好,这就为我们自定义滚动条提供了非常有利的条件。
一、ScrollBar的组成
ScrollBar由6个部分组成。两个行按钮、两个页按钮、一个滑块、一个轨道。
1.结构说明
一个简单的纵向滚动条如下:
纵向滚动组成如下:
一个简单的纵向滚动条如下:
横向滚动条与纵向滚动条结构一致,相当于纵向滚动条顺时针转90度:
2.具体组成
行按钮
行按钮可以是任意按钮类型,且在ScrollBar内不受布局位置的限制,可以任意摆放。标识行按钮的方式是Command绑定ScrollBar的LineCommand。
LineCommand有4种分别是:LineUpCommand、LineDownCommand、LineLeftCommand、LineRightCommand,共4个方向,分别两两对于纵向和横向的ScrollBar。
代码如下(示例):
(1)上行按钮
绑定ScrollBar.LineUpCommand即为上行按钮。
<RepeatButton Command="ScrollBar.LineUpCommand" />
(2)下行按钮
绑定ScrollBar.LineDownCommand即为下行按钮。
<RepeatButton Command="ScrollBar.LineDownCommand" />
(3)左行按钮
绑定ScrollBar.LineLeftCommand即为左行按钮。
<RepeatButton Command="ScrollBar.LineLeftCommand" />
(4)右行按钮
绑定ScrollBar.LineRightCommand即为右行按钮。
<RepeatButton Command="ScrollBar.LineRightCommand" />
页按钮
页按钮相对于行按钮有布局的要求,需要放在Track标签的Track.DecreaseRepeatButton或中Track.IncreaseRepeatButton标签中(Track是轨道标签第4节会说明)。
页按钮只能是RepeatButton类型,并且Command绑定ScrollBar的PageCommand。PageCommand有4钟,分别是LineUpCommand、LineDownCommand、LineLeftCommand、LineRightCommand,共4个方向,分别两两对于纵向和横向的ScrollBar。
代码如下(示例):
上页按钮
放在Track.DecreaseRepeatButton标签里并绑定ScrollBar.PageUpCommand即为上页按钮。
<Track.DecreaseRepeatButton>
<RepeatButton Command="ScrollBar.PageUpCommand" />
</Track.DecreaseRepeatButton>
下页按钮
放在Track.IncreaseRepeatButton标签里并绑定ScrollBar.PageDownCommand即为下页按钮。
<Track.IncreaseRepeatButton>
<RepeatButton Command="ScrollBar.PageDownCommand" />
</Track.IncreaseRepeatButton>
左页按钮
放在Track.DecreaseRepeatButton标签里并绑定ScrollBar.PageLeftCommand即为左页按钮。
<Track.DecreaseRepeatButton>
<RepeatButton Command="ScrollBar.PageLeftCommand" />
</Track.DecreaseRepeatButton>
右页按钮
放在Track.IncreaseRepeatButton标签里并绑定ScrollBar.PageRightCommand即为右页按钮。
<Track.IncreaseRepeatButton>
<RepeatButton Command="ScrollBar.PageRightCommand" />
</Track.IncreaseRepeatButton>
滑块
滑块必须是Thumb类型的标签,位置页必须放在Track的Track.Thumb子标签中(Track是轨道标签第4节会说明)。Thumb有Template属性,所以可以自定义样式。
<Track.Thumb>
<Thumb/>
</Track.Thumb>
Thumb的长度是自动计算的。其计算公式是:
thumbSize = (viewportSize/(maximum–minimum+viewportSize))×trackLength
如果想要Thumb固定长度,直接设置是没有效果的,必须先将Track的ViewportSize设置为NaN:
<Track ViewportSize="NaN" />
注:Thumb的长度是指,纵向滚动条Thumb的Height、横向滚动条Thumb的Width
轨道
ScrollBar的轨道是Track类型的标签,Track中包含了三部分:DecreaseRepeatButton、Thumb、IncreaseRepeatButton,分别对应页按钮和滑块。Track的Name属性必须设为 “PART_Track”,否则内部的按钮是无法控制滚动条的。
纵向轨道
<Track Name="PART_Track" IsDirectionReversed="true">
<Track.DecreaseRepeatButton>
<RepeatButton Command="ScrollBar.PageUpCommand"/>
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb/>
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Command="ScrollBar.PageDownCommand"/>
</Track.IncreaseRepeatButton>
</Track>
横向轨道
<Track Name="PART_Track" IsDirectionReversed="False">
<Track.DecreaseRepeatButton>
<RepeatButton Command="ScrollBar.PageLeftCommand"/>
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb/>
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Command="ScrollBar.PageRightCommand"/>
</Track.IncreaseRepeatButton>
</Track>
二、如何自定义?
1.确定参数
第一步需要确定有哪些参数是可以自己控制的,否则将缺乏灵活性。比如有两个页面需要滚动条,样式是一样的,唯一的区别是滑块宽度不同,为此自定义两个不同的滚动条,显然是不明智的。更好的做法应该是,设置一个滑块宽度的参数,在不同页面使用不同的参数。
参数的定义可以根据具体使用需求,以及对ScrollBar可拓展性要求来确定。
比如定义如下参数(示例):
<!--纵向滚动条宽度-->
<sys:Double x:Key="VerticalScrollBarThickness">4</sys:Double>
<!--纵向轨道背景色-->
<SolidColorBrush x:Key="VerticalTrackBackgroundBrush" Color="White" />
<!--横向滚动条宽度-->
<sys:Double x:Key="HorizontalScrollBarThickness">4</sys:Double>
<!--横向轨道背景色-->
<SolidColorBrush x:Key="HorizontalTrackBackgroundBrush" Color="White" />
参数的用法说明:
参数对象在Style或Template中通过DynamicResource的方式使用,比如上面的VerticalScrollBarThickness对象在Style中通过 <Setter Property="Width" Value="{DynamicResource VerticalScrollBarThickness}" />
的方式使用。或者在Template中<Border Width="{DynamicResource VerticalScrollBarThickness}" />
。
参数的赋值,是在Style使用处的Resources标签中定义同名的参数对象,并为其设置需要值。
2.定义Style
常规方法中,带ScrollBar的控件是无法获取到其ScrollBar对象并通过标签设置其属性的。在Style中自定义ScrollBar是比较好的方式。
定义Style标签有如下步骤:
(1)定义触发器
定义两个触发器,判段Orientation的属性,值为Vertical则设置纵向滚动条相关的属性值,反之值为Horizontal则设置横向向滚动条相关的属性值。
(2) 绑定参数
在上一节中有定义一些参数。在Style中就需要使用这些参数,一定要使用DynamicResource 去引用参数对象,否则将无法在页面使用时重新赋值。
(3)绑定Template
编写两个Template分别为VerticalScrollBar、HorizontalScrollBar(下一节有具体说明)。根据ScrollBar的Orientation属性来分别绑定不同的Template。
示例代码如下:
<Style x:Key="ScrollStyle_Example" TargetType="ScrollBar">
<Style.Triggers>
<Trigger Property="Orientation" Value="Horizontal">
<Setter Property="Width" Value="Auto" />
<Setter Property="Height" Value="{DynamicResource HorizontalScrollBarThickness}" />
<Setter Property="Template" Value="{DynamicResource HorizontalScrollBar}" />
</Trigger>
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="Width" Value="{DynamicResource VerticalScrollBarThickness}" />
<Setter Property="Height" Value="Auto" />
<Setter Property="Template" Value="{DynamicResource VerticalScrollBar}" />
</Trigger>
</Style.Triggers>
</Style>
3.定义Template
一个完整的ScrollBar.Template有6个部分,即文章开头提到的:两个行按钮、两个页按钮、一个滑块、一个轨道。
(1) 纵向Template
对于纵向的Template代码如下(示例):
<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type RangeBase}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition MaxHeight="40"/>
<RowDefinition Height="*"/>
<RowDefinition MaxHeight="40"/>
</Grid.RowDefinitions>
<!--上行按钮-->
<RepeatButton Command="ScrollBar.LineUpCommand"/>
<!--轨道-->
<Track Name="PART_Track" Grid.Row="1">
<Track.DecreaseRepeatButton>
<!--上页按钮-->
<RepeatButton Command="ScrollBar.PageUpCommand" />
</Track.DecreaseRepeatButton>
<Track.Thumb>
<!--滑块-->
<Thumb />
</Track.Thumb>
<Track.IncreaseRepeatButton>
<!--下页按钮-->
<RepeatButton Command="ScrollBar.PageDownCommand" />
</Track.IncreaseRepeatButton>
</Track>
<!--下行按钮-->
<RepeatButton Grid.Row="2" Command="ScrollBar.LineDownCommand"/>
</Grid>
</ControlTemplate>
(2)横向Template
对于横向的Template代码如下(示例):
<ControlTemplate x:Key="HorizontalScrollBar" TargetType="{x:Type RangeBase}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<!--左行按钮-->
<RepeatButton Command="ScrollBar.LineLeftCommand"/>
<!--轨道-->
<Track Name="PART_Track" Grid.Column="1">
<Track.DecreaseRepeatButton>
<!--左页按钮-->
<RepeatButton Command="ScrollBar.PageLeftCommand" />
</Track.DecreaseRepeatButton>
<Track.Thumb>
<!--滑块-->
<Thumb />
</Track.Thumb>
<Track.IncreaseRepeatButton>
<!--右页按钮-->
<RepeatButton Command="ScrollBar.PageRightCommand" />
</Track.IncreaseRepeatButton>
</Track>
<!--右行按钮-->
<RepeatButton Grid.Column="2" Command="ScrollBar.LineRightCommand"/>
</Grid>
</ControlTemplate>
四、使用方法
在Resources标签中使用自定义滚动条。
1.继承Style
定义一个新的StyleTargetType为ScrollBar,BasedOn上述自定义的ScrollBar Style,不能设置x:key值。
<Style TargetType="ScrollBar" BasedOn="{StaticResource ScrollStyle_Example}"></Style>
2.设置参数
根据第三章第1小节确定的参数,设置需要的参数值。比如将纵向滚动条宽度设为8像素:
<sys:Double x:Key="VerticalScrollBarThickness">8</sys:Double>
示例代码
以ListBox为例:
<ListBox>
<ListBox.Resources>
<!--替换ListBox中滚动条的样式-->
<Style TargetType="ScrollBar" BasedOn="{StaticResource ScrollStyle_Example}"></Style>
<!--纵向滚动条宽度为4像素-->
<sys:Double x:Key="VerticalScrollBarThickness">4</sys:Double>
<!--横向滚动条高度为4像素-->
<sys:Double x:Key="HorizontalScrollBarThickness">4</sys:Double>
</ListBox.Resources>
</ListBox>
五、具体例子
1.通用模板
根据上述步骤汇总出一个模板,对于ScrollBar的任何自定义拓展,都可以拷贝一份模板,在此模板的基础上定制修改。
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<!-- 1.确定参数 -->
<!--纵向滚动条宽度-->
<sys:Double x:Key="VerticalScrollBarThickness">4</sys:Double>
<!--纵向滑块颜色-->
<SolidColorBrush x:Key="VerticalTrackThumbBackgroundBrush" Color="#cccccc" />
<!--横向滚动条宽度-->
<sys:Double x:Key="HorizontalScrollBarThickness">4</sys:Double>
<!--横向滑块颜色-->
<SolidColorBrush x:Key="HorizontalTrackThumbBackgroundBrush" Color="#cccccc" />
<!-- 2.定义Style -->
<Style x:Key="ScrollStyle_Example" TargetType="ScrollBar">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Style.Triggers>
<Trigger Property="Orientation" Value="Horizontal">
<Setter Property="Width" Value="Auto" />
<Setter Property="Height" Value="{DynamicResource HorizontalScrollBarThickness}" />
<Setter Property="Template" Value="{DynamicResource HorizontalScrollBar}" />
</Trigger>
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="Width" Value="{DynamicResource VerticalScrollBarThickness}" />
<Setter Property="Height" Value="Auto" />
<Setter Property="Template" Value="{DynamicResource VerticalScrollBar}" />
</Trigger>
</Style.Triggers>
</Style>
<!-- 3.定义template -->
<!-- 纵向滚动条template -->
<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type RangeBase}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition MaxHeight="auto"/>
<RowDefinition Height="*"/>
<RowDefinition MaxHeight="auto"/>
</Grid.RowDefinitions>
<!--上行按钮-->
<RepeatButton Command="ScrollBar.LineUpCommand"/>
<!--轨道-->
<Track Name="PART_Track" Grid.Row="1">
<Track.DecreaseRepeatButton>
<!--上页按钮-->
<RepeatButton Command="ScrollBar.PageUpCommand" />
</Track.DecreaseRepeatButton>
<Track.Thumb>
<!--滑块-->
<Thumb Background="{DynamicResource VerticalTrackThumbBackgroundBrush}" />
</Track.Thumb>
<Track.IncreaseRepeatButton>
<!--下页按钮-->
<RepeatButton Command="ScrollBar.PageDownCommand" />
</Track.IncreaseRepeatButton>
</Track>
<!--下行按钮-->
<RepeatButton Grid.Row="2" Command="ScrollBar.LineDownCommand"/>
</Grid>
</ControlTemplate>
<!-- 横向滚动条template -->
<ControlTemplate x:Key="HorizontalScrollBar" TargetType="{x:Type RangeBase}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<!--左行按钮-->
<RepeatButton Command="ScrollBar.LineLeftCommand"/>
<!--轨道-->
<Track Name="PART_Track" Grid.Column="1">
<Track.DecreaseRepeatButton>
<!--左页按钮-->
<RepeatButton Command="ScrollBar.PageLeftCommand" />
</Track.DecreaseRepeatButton>
<Track.Thumb >
<!--滑块-->
<Thumb Background="{DynamicResource HorizontalTrackThumbBackgroundBrush}" />
</Track.Thumb>
<Track.IncreaseRepeatButton>
<!--右页按钮-->
<RepeatButton Command="ScrollBar.PageRightCommand" />
</Track.IncreaseRepeatButton>
</Track>
<!--右行按钮-->
<RepeatButton Grid.Column="2" Command="ScrollBar.LineRightCommand"/>
</Grid>
</ControlTemplate>
</ResourceDictionary>
2.仿移动端滚动条
https://blog.csdn.net/u013113678/article/details/120811416
3.音量调节滚动条
https://blog.csdn.net/u013113678/article/details/120819414
4.加减按钮滚动条
https://blog.csdn.net/u013113678/article/details/120843370
总结
wpf的ScrollBar具有很强的定制性,尤其是将其分成了6个部分,两个行按钮、两个页按钮、一个滑块、一个轨道。每个部分都可以定义其样式及布局,或者删减。非常好的解决了曾经Windows上滚动条难以修改的痛点。