"Microsoft Blend" - 类似连续拖动



Microsoft Blend允许通过连续拖动来改变Left, Top等属性的数值。用户在属性值框中单击,按住按钮并向左或向右拖动以减小/增大值。简单。

它的特殊之处在于,如果光标到达屏幕的左端或右端,用户仍然想要拖动更多,他们可以继续拖动,光标将从屏幕的另一端重新开始。

我试图在使用Thumb控件的WPF应用程序之一中做到这一点。使用DragDetla事件,如果我发现Thumb已经到达屏幕的边缘,我将其位置设置为远端。但这使得e.HorizontalChange的值与整个屏幕的宽度一样大。如何在拖动期间改变拇指的位置而不影响水平变化值?

我已经在WPF控件中实现了这一点,通过使用文本框和订阅事件,如:

  • PreviewMouseDown
  • MouseUp和
  • MouseMove
  • MouseEnter

拖动直到达到屏幕限制需要鼠标捕获或调用任何UIElement上可用的CaptureMouse方法。另一方面,您需要在某个点释放鼠标,这需要调用releasemouseccapture方法。解决方案可能是这样的:

声明一个枚举来为拖动方向建模

internal enum MouseDirections
{
    None,
    LeftRight,
    UpDown
}

声明一个类来跟踪鼠标的起始位置(第一个位置)和当前位置:

internal class MouseIncrementor
{
    private MouseDirections _enumMouseDirection = MouseDirections.None;
    private Point _objPoint;
    private readonly Point _initialPoint;
    public MouseIncrementor(Point objPoint, MouseDirections enumMouseDirection)
    {
        _objPoint = objPoint;
        _initialPoint = _objPoint;
        _enumMouseDirection = enumMouseDirection;
    }
    public MouseDirections MouseDirection
    {
        get
        {
            return _enumMouseDirection;
        }
        protected set
        {
            _enumMouseDirection = value;
        }
    }
    public Point InitialPoint
    {
        get
        {
            return _initialPoint;
        }
    }
    public Point Point
    {
        get
        {
            return _objPoint;
        }
        set
        {
            _objPoint = value;
        }
    }
    internal MouseDirections SetMouseDirection(Point pos)
    {
        double deltaX = this.Point.X - pos.X;
        double deltaY = this.Point.Y - pos.Y;
        if (Math.Abs(deltaX) > Math.Abs(deltaY))
            MouseDirection = MouseDirections.LeftRight;
        else
        {
            if (Math.Abs(deltaX) < Math.Abs(deltaY))
                MouseDirection = MouseDirections.UpDown;
        }
        return MouseDirection;
    }
}

我有一个自定义控件,包含一个TextBox命名为_PART_TextBox:文本框_PART_TextBox;

…和MouseIncrementor字段:MouseIncrementor _objMouseIncr;

…它们是这样连接的:

            _PART_TextBox.MouseEnter += _PART_TextBox_MouseEnter;
            _PART_TextBox.GotKeyboardFocus += _PART_TextBox_GotKeyboardFocus;
            _PART_TextBox.LostKeyboardFocus += _PART_TextBox_LostKeyboardFocus;
            _PART_TextBox.MouseMove += _PART_TextBox_MouseMove;
            _PART_TextBox.MouseUp += _PART_TextBox_MouseUp;
            _PART_TextBox.PreviewMouseDown += _PART_TextBox_PreviewMouseDown;
            _PART_TextBox.LostMouseCapture += _PART_TextBox_LostMouseCapture;

和一些事件处理程序需要使其工作:

    private void _PART_TextBox_LostMouseCapture(object sender, MouseEventArgs e)
    {
        _objMouseIncr = null;
    }
    private void _PART_TextBox_MouseUp(object sender, MouseButtonEventArgs e)
    {
        if (_objMouseIncr != null)
        {
            var mouseUpPosition = GetPositionFromThis(e);
            if (_objMouseIncr.InitialPoint.Equals(mouseUpPosition))
            {
                _PART_TextBox.Focus();
            }
        }
        _PART_TextBox.ReleaseMouseCapture();
        _objMouseIncr = null;
    }
    private void _PART_TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        if (IsKeyboardFocusWithin == false)
        {
            _objMouseIncr = new MouseIncrementor(this.GetPositionFromThis(e), MouseDirections.None);
            e.Handled = true;
        }
    }
    private void _PART_TextBox_MouseMove(object sender, MouseEventArgs e)
    {
        // nothing to do here
        if (_objMouseIncr == null)
            return;
        if (e.LeftButton != MouseButtonState.Pressed)
            return;
        if (CanIncreaseCommand() == false && CanDecreaseCommand() == false)
        {
            // since we can't parse the value, we are out of here, i.e. user put text in our number box
            _objMouseIncr = null;
            return;
        }
        var pos = GetPositionFromThis(e);
        double deltaX = _objMouseIncr.Point.X - pos.X;
        double deltaY = _objMouseIncr.Point.Y - pos.Y;
        if (_objMouseIncr.MouseDirection == MouseDirections.None)
        {
            // this is our first time here, so we need to record if we are tracking x or y movements
            if (_objMouseIncr.SetMouseDirection(pos) != MouseDirections.None)
                _PART_TextBox.CaptureMouse();
        }
        if (_objMouseIncr.MouseDirection == MouseDirections.LeftRight)
        {
            if (deltaX > 0)
                OnDecrement(LargeStepSize);
            else
            {
                if (deltaX < 0)
                    OnIncrement(LargeStepSize);
            }
        }
        else
        {
            if (_objMouseIncr.MouseDirection == MouseDirections.UpDown)
            {
                if (deltaY > 0)
                {
                    if (CanIncreaseCommand() == true)
                        OnIncrease();
                }
                else
                {
                    if (deltaY < 0)
                    {
                        if (CanDecreaseCommand() == true)
                            OnDecrease();
                    }
                }
            }
        }
        _objMouseIncr.Point = GetPositionFromThis(e);
    }
    private Point GetPositionFromThis(MouseEventArgs e)
    {
        return this.PointToScreen(e.GetPosition(this));
    }
    private void _PART_TextBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        _objMouseIncr = null;
        (sender as TextBox).Cursor = Cursors.ScrollAll;
    }
    private void _PART_TextBox_MouseEnter(object sender, MouseEventArgs e)
    {
        if (IsMouseDragEnabled == false)
            return;
        if (IsKeyboardFocusWithin)
            (sender as TextBox).Cursor = Cursors.IBeam;
        else
            (sender as TextBox).Cursor = Cursors.ScrollAll;
    }
    private void _PART_TextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        _objMouseIncr = null;
        (sender as TextBox).Cursor = Cursors.IBeam;
    }

完整的项目位于这里:https://github.com/Dirkster99/NumericUpDownLib

请让我知道,如果我错过了什么或如果有其他问题。

最新更新