我知道这不是最好的用户体验,但我仍希望实现这一点:
任何时候shift
被按下,我希望我的usercontrol
(基本上是一个滑块)让Thumb
(以及它的Value
)移动两倍它通常应该。
这是我到目前为止所做的。
public partial class CustomSlider : UserControl
{
public CustomSlider()
{
InitializeComponent();
CMiXSlider.ApplyTemplate();
Thumb thumb0 = (CMiXSlider.Template.FindName("PART_Track", CMiXSlider) as Track).Thumb;
thumb0.MouseEnter += new MouseEventHandler(thumb_MouseEnter);
}
private void thumb_MouseEnter(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && e.MouseDevice.Captured == null)
{
MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Left);
args.RoutedEvent = MouseLeftButtonDownEvent;
(sender as Thumb).RaiseEvent(args);
}
}
Point pStart;
Point pCurrent;
Point pCenter;
bool isDragging;
private void CMiXSlider_DragStarted(object sender, DragStartedEventArgs e)
{
isDragging = true;
if (Keyboard.IsKeyDown(Key.LeftShift))
{
pStart = Mouse.GetPosition(CMiXSlider);
}
}
private void CMiXSlider_DragDelta(object sender, DragDeltaEventArgs e)
{
pCurrent = Mouse.GetPosition(CMiXSlider);
if (Keyboard.IsKeyDown(Key.LeftShift) == true )
{
pCenter.X = Math.Abs(pCurrent.X - pStart.X);
pCenter.Y = Math.Abs(pCurrent.Y - pStart.Y);
Value = (1.0 / CMiXSlider.ActualWidth) * pCenter.X/2 + (1.0 / CMiXSlider.ActualWidth)*pStart.X;
if (Value >= 1.0)
{
Value = 1.0;
}
else if (Value <= 0.0)
{
Value = 0.0;
}
}
}
private void CMiXSlider_DragCompleted(object sender, DragCompletedEventArgs e)
{
isDragging = false;
}
private void CMiXSlider_KeyDown(object sender, KeyEventArgs e)
{
if (Keyboard.IsKeyDown(Key.LeftShift) && isDragging == true)
{
pStart = Mouse.GetPosition(CMiXSlider);
}
}
和XAML:
<UserControl x:Class="CMiX.CustomSlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CMiX"
mc:Ignorable="d"
d:DesignHeight="116.3" d:DesignWidth="567.2">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/CMiX_UserControl;component/RessourceDictionnaries/Brushes/GenericBrushes.xaml"/>
<ResourceDictionary Source="/CMiX_UserControl;component/RessourceDictionnaries/Styles/BaseSliderStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Slider x:Name="CMiXSlider" Style="{StaticResource BaseSliderStyle}" Margin="1"
Thumb.DragDelta="CMiXSlider_DragDelta"
Thumb.DragStarted="CMiXSlider_DragStarted"
Orientation="{Binding Orientation, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type local:CustomSlider}}}"
Value="{Binding Value, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type local:CustomSlider}}}"
IsMoveToPointEnabled="False" Minimum="0.0" Maximum="1.0" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch"/>
但很少有问题。现在我必须先按Shift
然后拖动,否则如果我先开始拖动然后移动,拇指会向后跳。
我在某处遗漏了一些逻辑。
有什么建议吗?
谢谢
答案 0 :(得分:2)
您可以做的是,每次迭代都会将更改处理为Value
,以便您可以处理拖动的当前“速度”。
对于这个例子,我假设您拥有DependencyProperties Minimum
,Maximum
和Value
,就像任何基于RangeBase
的控件一样(Slider
,{{ 1}}等。)。
此示例中的许多变量都是不必要的,仅用于演示计算中的步骤
ProgressBar
应该是这样的:
或者(如果这不够“精确”),您可以根据 Shift 状态发生变化的最后位置处理更改。
完整代码供参考:
private void CMiXSlider_OnDragStarted(object sender, DragStartedEventArgs e)
{
_lastPos = GetMousePosition();
}
private double GetMousePosition()
{
return Mouse.GetPosition(this).X;
}
private void CMiXSlider_OnDragDelta(object sender, DragDeltaEventArgs e)
{
double thumbPosition = GetMousePosition();
double deltaX = thumbPosition - _lastPos;
_lastPos = thumbPosition;
if (Keyboard.IsKeyDown(Key.LeftShift))
deltaX /= 2;
double effectiveLength = ActualWidth - CMiXSlider.ActualWidth;
double effectiveChange = deltaX / effectiveLength;
double valueRange = Maximum - Minimum;
Value = Math.Min(Maximum, Math.Max(Minimum, Value + effectiveChange * valueRange));
RepositionThumb();
}
private void RepositionThumb()
{
double relativePosition = (Value - Minimum) / (Maximum - Minimum);
double absolutePosition = (ActualWidth - CMiXSlider.ActualWidth) * relativePosition;
CMiXSlider.Margin = new Thickness(absolutePosition,0,0,0);
}
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace ShiftSlider
{
public partial class CustomSlider : UserControl
{
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
"Minimum", typeof(double), typeof(CustomSlider), new PropertyMetadata((double)0.0));
public double Minimum
{
get { return (double) GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
"Maximum", typeof(double), typeof(CustomSlider), new PropertyMetadata((double)100.0));
public double Maximum
{
get { return (double) GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(double), typeof(CustomSlider), new PropertyMetadata(default(double)));
private double _lastPos;
public double Value
{
get { return (double) GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public CustomSlider()
{
InitializeComponent();
}
private void CMiXSlider_OnDragStarted(object sender, DragStartedEventArgs e)
{
e.Handled = true;
_lastPos = GetMousePosition();
}
private double GetMousePosition()
{
return Mouse.GetPosition(this).X;
}
private void CMiXSlider_OnDragDelta(object sender, DragDeltaEventArgs e)
{
e.Handled = true;
double thumbPosition = GetMousePosition();
double deltaX = thumbPosition - _lastPos;
_lastPos = thumbPosition;
if (Keyboard.IsKeyDown(Key.LeftShift))
deltaX /= 2;
double effectiveLength = ActualWidth - CMiXSlider.ActualWidth;
double effectiveChange = deltaX / effectiveLength;
double valueRange = Maximum - Minimum;
Value = Math.Min(Maximum, Math.Max(Minimum, Value + effectiveChange * valueRange));
RepositionThumb();
}
private void RepositionThumb()
{
double relativePosition = (Value - Minimum) / (Maximum - Minimum);
double absolutePosition = (ActualWidth - CMiXSlider.ActualWidth) * relativePosition;
CMiXSlider.Margin = new Thickness(absolutePosition,0,0,0);
}
private void CMiXSlider_OnDragCompleted(object sender, DragCompletedEventArgs e)
{
//
}
}
}
<UserControl x:Class="ShiftSlider.CustomSlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="20">
<Grid>
<Rectangle Fill="LightGray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Thumb VerticalAlignment="Stretch" HorizontalAlignment="Left" Width="20" Name="CMiXSlider"
DragStarted="CMiXSlider_OnDragStarted" DragDelta="CMiXSlider_OnDragDelta"
DragCompleted="CMiXSlider_OnDragCompleted"/>
</Grid>
</UserControl>