效果

概述
最近有个小需求要用双滑块表示一个取值范围,于是就简单做了个用户控件,在此记录下.
使用矩形Rectangle表示范围,椭圆Ellipse表示滑块,使用Canvas控制滑块的左右移动.
椭圆的鼠标按下事件里强制获取鼠标事件焦点,避免移动过快或移出控件范围时,滑块就不跟着跑了.椭圆的鼠标抬起事件释放强制获取鼠标事件焦点
代码部分
需求比较简单,只定义了4个依赖属性,范围的最大值和最小值,取值的最大值和最小值.
接下来就是计算滑块和高亮矩形的位置,计算时注意减去椭圆Ellipse控件(圆)的半径,使圆心对准值,而不是左侧对准值.
鼠标移动的时候,计算当前位置对应的值,去改变依赖属性的值:- 1 private void ell_MouseMove(object sender, MouseEventArgs e)
- 2 {
- 3 if (e.LeftButton == MouseButtonState.Pressed)
- 4 {
- 5 double percentage = e.GetPosition(rect).X / rect.ActualWidth;
- 6 double value = (Maximum - Minimum) * percentage + Minimum;
- 7 if (_ellFromPressed)
- 8 {
- 9 MinValue = (int)value;
- 10
- 11 }
- 12 if (_ellToPressed)
- 13 {
- 14 MaxValue = (int)value;
- 15 }
- 16 }
- 17 }
复制代码
依赖属性的值变化,引起滑块的位置变化和高亮滑块宽度和位置的变化:- 1 //最小值变化
- 2 private void MinValuePropertyChanged()
- 3 {
- 4 if (MinValue < Minimum)
- 5 {
- 6 MinValue = Minimum;
- 7 return;
- 8 }
- 9 if (MinValue > MaxValue)
- 10 {
- 11 MaxValue = MinValue;
- 12 }
- 13 //滑块位置变化
- 14 _offsetFrom = (MinValue - Minimum) * rect.ActualWidth / (Maximum - Minimum) - 8;
- 15 Canvas.SetLeft(ellFrom, _offsetFrom);
- 16 //高亮矩形长度和位置的变化
- 17 if (_offsetTo != -1)
- 18 {
- 19 double diff = _offsetTo - _offsetFrom;
- 20 if (diff >= 0)
- 21 {
- 22 rectHighLight.Width = diff;
- 23 Canvas.SetLeft(rectHighLight, _offsetFrom);
- 24 }
- 25 }
- 26 }
- 27
- 28 //最大值变化
- 29 private void MaxValuePropertyChanged()
- 30 {
- 31 if (MaxValue > Maximum)
- 32 {
- 33 MaxValue = Maximum;
- 34 return;
- 35 }
- 36 if (MaxValue < MinValue)
- 37 {
- 38 MinValue = MaxValue;
- 39 }
- 40 //滑块位置变化
- 41 _offsetTo = (MaxValue - Minimum) * rect.ActualWidth / (Maximum - Minimum) - 8;
- 42 Canvas.SetLeft(ellTo, _offsetTo);
- 43 //高亮矩形长度和位置的变化
- 44 if (_offsetFrom != -1)
- 45 {
- 46 double diff = _offsetTo - _offsetFrom;
- 47 if (diff >= 0)
- 48 {
- 49 rectHighLight.Width = diff;
- 50 Canvas.SetLeft(rectHighLight, _offsetFrom);
- 51 }
- 52 }
- 53 }
复制代码
取值的TextBox没有封装在用户控件里,是单独的两个TextBox跟依赖属性双向绑定的.注意绑定的时候触发方式最好不要用PropertyChanged,没有防抖效果,不然体验不是很好.回车触发就可以了.
前台双向绑定:- 1 <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
- 2 <local:DoubleThumbSlider x:Name="dts" Width="500" Minimum="100" Maximum="200"></local:DoubleThumbSlider>
- 3 <TextBox Name="tMin" Width="48" Text="{Binding ElementName=dts,Path=MinValue,UpdateSourceTrigger=Explicit,Mode=TwoWay}" PreviewKeyUp="tbox_PreviewKeyUp"></TextBox>
- 4 <TextBlock Margin="5,0" Text="-"></TextBlock>
- 5 <TextBox Name="tMax" Width="48" Text="{Binding ElementName=dts,Path=MaxValue,UpdateSourceTrigger=Explicit,Mode=TwoWay}" PreviewKeyUp="tbox_PreviewKeyUp"></TextBox>
- 6 </StackPanel>
复制代码
后台回车触发:- 1 private void tbox_PreviewKeyUp(object sender, KeyEventArgs e)
- 2 {
- 3 if (e.Key == Key.Enter)
- 4 {
- 5 TextBox tbox = (TextBox)sender;
- 6 var binding = tbox.GetBindingExpression(TextBox.TextProperty);
- 7 binding.UpdateSource();
- 8 }
- 9 }
复制代码
源码下载:DoubleThumbSlider.zip
参考连接:
1.https://docs.microsoft.com/zh-cn/dotnet/api/system.windows.uielement.capturemouse?view=windowsdesktop-6.0
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |