0

WPF双滑块控件以及强制捕获鼠标事件焦点 - 普通的地球人

 4 months ago
source link: https://www.cnblogs.com/tsliwei/p/16440364.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

WPF双滑块控件以及强制捕获鼠标事件焦点

918258-20220703170252392-1958990535.gif

最近有个小需求要用双滑块表示一个取值范围,于是就简单做了个用户控件,在此记录下.

使用矩形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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK