开发者

How do I only allow dragging in a circular path?

开发者 https://www.devze.com 2023-01-20 18:38 出处:网络
Is it possible to restrict the drag source to only move within the 开发者_运维技巧boundaries of a circular path when dragging it?You don\'t need the 360-point path.Instead, as you are dragging, comput

Is it possible to restrict the drag source to only move within the 开发者_运维技巧boundaries of a circular path when dragging it?


You don't need the 360-point path. Instead, as you are dragging, compute the current angle using Math.Atan2(Y,X), and then generate the point on the circle. You would still need to compute center and radius on resize and store them, or compute them inside MouseMove.

    private void UserControl_MouseMove(object sender, MouseEventArgs e)
    {
        if (!isDraggingMarker)
            return;
        var position = e.GetPosition(this);

        double angle = Math.Atan2(position.Y - center.Y, position.X - center.X);
        var closest = new Point(center.X + radius*Math.Cos(angle),
                                center.Y + radius*Math.Sin(angle));

        SetMarkerPosition(closest);
    }


Create a circle of points and then when the mouse moves (and we are dragging) calculate the nearest point and snap to that point.

CircularDrag.xaml

<UserControl x:Class="DraggingBoundaries.CircularDrag"
         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:DesignHeight="300" d:DesignWidth="300"
         SizeChanged="UserControl_SizeChanged"
         MouseMove="UserControl_MouseMove"
         MouseLeave="UserControl_MouseLeave"
         MouseLeftButtonUp="UserControl_MouseLeftButtonUp"
         >
    <Grid Background="White">
        <Border 
            x:Name="Marker"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Width="14" 
            Height="14" 
            Background="CornflowerBlue" 
            CornerRadius="2" 
            BorderThickness="1" 
            BorderBrush="DarkGray"
            MouseLeftButtonDown="Marker_MouseLeftButtonDown"
            />
    </Grid>
</UserControl>

CircularDrag.xaml.cs

using System;
using System.Linq;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace DraggingBoundaries
{
    public partial class CircularDrag : UserControl
    {
        List<Point> allowedWheelMarkerPositions;
        bool isDraggingMarker;

        public CircularDrag()
        {
            InitializeComponent();
        }

        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            var center = new Point(e.NewSize.Width / 2, e.NewSize.Height / 2);

            var radius = (center.X < center.Y ? center.X : center.Y) - 15;

            allowedWheelMarkerPositions = CreateCirclePath(center, radius);
            SetMarkerPosition(allowedWheelMarkerPositions.First());
        }

        private List<Point> CreateCirclePath(Point center, double radius)
        {
            var result = new List<Point>();
            for (double angle = 0; angle <= 360; angle++)
            {
                double angleR = angle * (Math.PI / 180);
                double x = center.X + Math.Cos(angleR) * radius;
                double y = center.Y - Math.Sin(angleR) * radius;

                result.Add(new Point(x, y));
            }
            return result;
        }

        private void UserControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (!isDraggingMarker)
                return;
            var position = e.GetPosition(this);

            var closest = allowedWheelMarkerPositions
                .OrderBy(p => GetDistance(position, p))
                .First();

            SetMarkerPosition(closest);
        }

        private void SetMarkerPosition(Point closest)
        {
            Marker.Margin = new Thickness(closest.X - Marker.Width / 2, closest.Y - Marker.Height / 2, 0, 0);
        }

        private double GetDistance(Point a, Point b)
        {
            var deltaX = a.X - b.X;
            var deltaY = a.Y - b.Y;

            return Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2));
        }

        private void Marker_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            isDraggingMarker = true;
        }

        private void UserControl_MouseLeave(object sender, MouseEventArgs e)
        {
            isDraggingMarker = false;
        }

        private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            isDraggingMarker = false;
        }
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消