0x01. 概要
WPF 自带的拖动条控件是 Slider
, 其默认样式为:
这种风格一般很难和实际的APP匹配, UI肯定会给一种自己的APP风格的拖动条. 最简单的莫过于修改滑块图案, 滑轨颜色等等. 如:
0x02. Slider组成
根据微软官方的文档, 一个Slider如下组成:
从上图我们可以看出, Slider的简单组成为: Track 和 TickBar, 其中Track包括:
- Thumb : 滑块
- RepeatButton : 重复的按钮, 即滑轨. 分为两段, 增量部分和减量部分.
TickBar为刻度标尺, 可选.
0x03. 自定义Slider风格
和其他WPF控件的自定义一样, 可以在 Window
标签的 Resource
中直接定义 Style
, 也可以在 Slider
标签内自定义.
首先自定义 Thumb
部分, 把 Thumb
改为一个灰色边儿的白色圆形:
<Style TargetType="{x:Type Thumb}" x:Key="SliderThumbStyle">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Height" Value="15"/>
<Setter Property="Width" Value="15"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border BorderBrush="#FFEBEBEB" BorderThickness="1" CornerRadius="7">
<Ellipse Width="14" Height="14" Fill="White"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
其次是定义 RepeatButton
, 分为 IncreaseRepeatButton
和 DecreaseRepeatButton
, 这里我们将两种 Button 定义为一样的颜色和形状:
<Style TargetType="{x:Type RepeatButton}" x:Key="SliderIncreaseButtonStyle">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Width="4" Background="#FFEBEBEB" SnapsToDevicePixels="True"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type RepeatButton}" x:Key="SliderDecreaseButtonStyle">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Width="4" Background="#FFEBEBEB" SnapsToDevicePixels="True"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
接下来是组合上面的 Thumb
和 RepeatButton
:
<Style x:Key="SliderStyle1" TargetType="{x:Type Slider}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Slider}">
<Grid>
<Track >
<Track.DecreaseRepeatButton>
<RepeatButton
Style="{StaticResource SliderDecreaseButtonStyle}"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton
Style="{StaticResource SliderIncreaseButtonStyle}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Focusable="False"
Style="{StaticResource SliderThumbStyle}"
VerticalAlignment="Top"/>
</Track.Thumb>
</Track>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
在 Track内部包括了 IncreaseRepeatButton
, Thumb
, DecreaseRepeatButton
. 组合好以后应用到 Slider中:
<Grid>
<Slider Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center"
SnapsToDevicePixels="True" Maximum="10" MinHeight="100"
Style="{DynamicResource SliderStyle1}">
</Slider>
</Grid>
然后运行项目, 你会发现 Slider 已经和上面的图一样了:
但是, 当你拖动滑块的时候会发现拖不动!
这是为什么? 官网给出了 Slider 的自定义说明文档: Slider Styles and Templates | Microsoft Docs, 根据文档说明代码, 你会发现组合 Track的代码:
<Track Grid.Column="1"
x:Name="PART_Track">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource SliderButtonStyle}"
Command="Slider.DecreaseLarge" />
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource SliderThumbStyle}" />
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource SliderButtonStyle}"
Command="Slider.IncreaseLarge" />
</Track.IncreaseRepeatButton>
</Track>
经过一步步删除代码发现, 当删除**x:Name=PART_Track
** 这部分的时候, 滑块就无法滑动!
所以自定义时一定要给 Track 添加 x:Name=PART_Track
, 保证滑块可以滑动!!!
所以自定义时一定要给 Track 添加 x:Name=PART_Track
, 保证滑块可以滑动!!!
所以自定义时一定要给 Track 添加 x:Name=PART_Track
, 保证滑块可以滑动!!!
这是个很不起眼的坑, 请多加小心.
为什么没有这个名字就无法滑动呢?
我们打开 Slider 的源码查看:
namespace System.Windows.Controls
{
/// <summary>Represents a control that lets the user select from a range of values by moving a <see cref="P:System.Windows.Controls.Primitives.Track.Thumb" /> control along a <see cref="T:System.Windows.Controls.Primitives.Track" />.</summary>
[Localizability(LocalizationCategory.Ignore)]
[DefaultEvent("ValueChanged")]
[DefaultProperty("Value")]
[TemplatePart(Name = "PART_Track", Type = typeof (Track))]
[TemplatePart(Name = "PART_SelectionRange", Type = typeof (FrameworkElement))]
public class Slider : RangeBase
{
//...其他代码
private const string TrackName = "PART_Track";
private const string SelectionRangeElementName = "PART_SelectionRange";
//...其他代码
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.SelectionRangeElement = this.GetTemplateChild("PART_SelectionRange") as FrameworkElement;
this.Track = this.GetTemplateChild("PART_Track") as Track;
if (this._autoToolTip == null)
return;
this._autoToolTip.PlacementTarget = this.Track != null ? (UIElement) this.Track.Thumb : (UIElement) null;
}
}
在其源码内部的是直接硬编码了 PART_Track
这个名称的, 所以如果不写名字或者修改名字都会导致无法滑动.
评论区