精确定位滑块拇指

时间:2017-05-30 07:32:04

标签: c# wpf

我知道这不是最好的用户体验,但我仍希望实现这一点:

任何时候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然后拖动,否则如果我先开始拖动然后移动,拇指会向后跳。

我在某处遗漏了一些逻辑。

有什么建议吗?

谢谢

1 个答案:

答案 0 :(得分:2)

您可以做的是,每次迭代都会将更改处理为Value,以便您可以处理拖动的当前“速度”。

对于这个例子,我假设您拥有DependencyProperties MinimumMaximumValue,就像任何基于RangeBase的控件一样(Slider,{{ 1}}等。)。

此示例中的许多变量都是不必要的,仅用于演示计算中的步骤

ProgressBar

应该是这样的:

Thumb Animation

或者(如果这不够“精确”),您可以根据 Shift 状态发生变化的最后位置处理更改。

完整代码供参考:

C#:

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);
}

XAML:

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>