当项目需要双滑块时,网上基本上可以是单滑块的样式和例子,但很少有双滑块。后来,我终于在网上找到了一个伟大的神的帖子。通过修改和改进,我终于满足了自己的需要,但后来我在查看代码时似乎不明白。现在我重新整理并记录下来,以备将来查看。
WPF中的Slider,看他的模板很复杂,粗略想想MultiRangeSlider只是几个滑块(Thumb),添加几个矩形,一个滑块对应两个矩形,当滑块移动时,不是两侧矩形宽度的变化,矩形我们只是想注意宽度的变化,不想调整他的实际位置,什么容器安装矩形,StackPanel,里面的对象总是首尾相连,但要做到Thumb能水平移动,在StackPanel中间显示不合适,然后放入Canvas然后使用这两个容器Grid叠在一起,Canvas在上面,就是这样。
<Grid> <StackPanel Margin="15,0,15,0" x:Name="RangeContainer" Orientation="Horizontal"> </StackPanel> <Canvas x:Name="ThumbContainer"> </Canvas> </Grid>
为了让滑块看起来好看,给滑块做个样式:
<Style TargetType="local:ThumbEx"> <Setter Property="Width" Value="30"></Setter> <Setter Property="Height" Value="100"></Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Thumb"> <Grid> <StackPanel> <Rectangle SnapsToDevicePixels="True" Height="55" RadiusX="1" RadiusY="1" StrokeThickness="10" Stroke="#FF158BCF" Fill="#FF158BCF"></Rectangle> </StackPanel> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
在我自己的项目中,最终的目标是这样的:

所以代码更改后就是这样。
<UserControl.Background> <ImageBrush ImageSource="1.png?x-oss-process=image/watermark,g_center,image_YXJ0aWNsZS9wdWJsaWMvd2F0ZXJtYXJrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSxQXzQwCg==,t_20" Stretch="Uniform"/> </UserControl.Background> <UserControl.Resources> <Style TargetType="local:ThumbEx"> <Setter Property="Width" Value="30"></Setter> <Setter Property="Height" Value="100"></Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Thumb"> <Grid> <StackPanel> <Rectangle SnapsToDevicePixels="True" Height="55" RadiusX="1" RadiusY="1" StrokeThickness="10" Stroke="#FF158BCF" Fill="#FF158BCF"></Rectangle> </StackPanel> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources> <Grid > <StackPanel Margin="15,0,15,0" x:Name="RangeContainer" Orientation="Horizontal"> </StackPanel> <Canvas x:Name="ThumbContainer"> </Canvas> </Grid>
为了方便多次使用,我们使用它UserControl当然,定义这个控件必须支持各种数据Binding啊,对于这个控制器,我不需要知道外部是什么样的数据结构,我只需要知道我需要显示多个滑块,所以必须有一个描述Range的数据结构
public class RangeItem { #region 字段 private double _from; private double _to; private string _name; private double _maxDuration; private bool _isStatic; private double _duration; #endregion #region 属性 public double From { get { return _from; } set { _from = value; } } public double To { get { return _to; } set { _to = value; } } /// <summary> /// 是否静止 /// </summary> public bool IsStatic { get { return _isStatic; } set { _isStatic = value; } } public double Duration { get { return _duration; } set { _duration = value; } } public double MaxDuration { get {
return _maxDuration;
}
set
{
_maxDuration = value;
}
}
#endregion
}
重要的属性有From(起始值),To(结束值),MaxDuration(总长),
根据这一个数据,我们就能生成一个矩形。整个Slider的宽度是固定的,所以就可以根据(To-From)/MaxDuration*Slider长度,就能计算出这个矩形的宽度,直接加入StackPanel就行。
矩形加进去了,现在加滑块,因为滑块是在Canvas中的,所以他需要确切知道Canvas.Left附加属性,这个Left不就左边矩形的宽度么。在把滑块和左右两边的矩形关联起来,因为矩形的拖动事件需要实时去改变两边的矩形的宽度。
private static double m_ThumbWidth;
public void SetLeft(double length)
{
length = length / 100 * m_ThumbWidth - 15;
Canvas.SetLeft(_thumbExs[0], length);
}
public void SetRight(double length)
{
length = length / 100 * m_ThumbWidth + 15;
Canvas.SetRight(_thumbExs[1], length);
}
要跟后端的数据绑定,也就是三个矩形的宽度关联
MultiSlider x:Name="mSlider" RangeItems="{Binding Items}"
下方就是加入滑块两端,也就是三个矩形的宽度
#region 初始化滑块
mSlider.ControlWidth = mSlider.Width;
Items.Add(new RangeItem()
{
From = 0,
To = 0,
IsStatic = true,
MaxDuration = 100
});
Items.Add(new RangeItem()
{
From = 0,
To = 100,
IsStatic = false,
MaxDuration = 100
});
Items.Add(new RangeItem()
{
From = 100,
To = 100,
IsStatic = false,
MaxDuration = 100
});
this.DataContext = this;
#endregion
同时需要这段代码:
#region 多滑块slider
private ObservableCollection<RangeItem> _items = new ObservableCollection<RangeItem>();
public ObservableCollection<RangeItem> Items
{
get
{
return _items;
}
set
{
_items = value;
}
}
#endregion
基本就这样,暂时满足自己的需求,时间长了回头过来写,有些啥意思自己都有点弄不明白了,凑合着看