简体   繁体   English

WPF自定义控件单击和拖动/跟随鼠标指针

[英]WPF Custom Control Click and Drag / Follow Mouse Pointer

I have read various solutions to the problem and I now wonder which one is to be preferred in which situation (and mine especially) 我已经阅读了解决该问题的各种解决方案,现在我想知道在哪种情况下(尤其是我的情况)首选哪种解决方案

I have created a Custom Control that Renders a Color wheel and a circle ( Ellipse ) on a canvas in the middle. 我创建了一个自定义控件,该控件在中间的画布上渲染一个色轮和一个圆形( Ellipse )。 I now want to be able to click and drag that circle as a selector on the color wheel. 现在,我希望能够单击并拖动该圆圈作为色轮上的选择器。

Possible solutions include: Overriding the OnClick and / or OnMouseMove events and update the circles position by either dependency properties or using TemplateParts or even generating the circle in the Controls Code Behind. 可能的解决方案包括:覆盖OnClick和/或OnMouseMove事件,并通过依赖项属性或使用TemplateParts甚至在“后面的控件代码”中生成圆来更新圆的位置。

I wonder if it would also be possible to use triggers in XAML to achieve this effect and which solution would deliver the "smoothest" motion. 我想知道是否还可以在XAML中使用触发器来实现这种效果,以及哪种解决方案可以实现“最流畅的”运动。

Update 1: To address comments, here is some code: 更新1:要解决评论,下面是一些代码:

ColorPicker.xaml ColorPicker.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:TrigDebugUtil.Controls">


    <Style x:Key="ColorPicker" TargetType="{x:Type local:ColorPicker}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ColorPicker}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Image Source="{TemplateBinding ColorWheelImage}" Width="500" Height="500"/>
                            <Canvas Width="10" Height="10" HorizontalAlignment="Center" VerticalAlignment="Center">
                                <Ellipse Fill="{TemplateBinding Property=SelectedColor}" Width="10" Height="10" Stroke="Black" StrokeThickness=".5" />
                            </Canvas>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

ColorPicker.cs ColorPicker.cs

namespace TrigDebugUtil.Controls
{
    public class ColorPicker : Control
    {
        #region Private Fields

        #endregion //Private Fields

        #region Dependency Properties
        public static readonly DependencyProperty ColorWheelImageProperty = DependencyProperty.Register("ColorWheelImage", typeof(WriteableBitmap), typeof(ColorPicker));
        public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register("SelectedColor", typeof(SolidColorBrush), typeof(ColorPicker));
        #endregion //Dependency Properties

        #region Properties
        public WriteableBitmap ColorWheelImage
        {
            get { return (WriteableBitmap)GetValue(ColorWheelImageProperty); }
            private set { SetValue(ColorWheelImageProperty, value);  }
        }

        public SolidColorBrush SelectedColor
        {
            get { return (SolidColorBrush)GetValue(SelectedColorProperty); }
            private set { SetValue(SelectedColorProperty, value); }
        }
        #endregion //Properties

        static ColorPicker()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));
        }

        public ColorPicker()
        {
            ColorWheelImage = new WriteableBitmap(500, 500, 96, 96, PixelFormats.Rgb24, null);
            SelectedColor = Brushes.White;
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            Byte[] pixels = new Byte[1500 * 500];

            // Update algo here


            ColorWheelImage.WritePixels(new Int32Rect(0, 0, 500, 500), pixels, 1500, 0);

        }
    }
}

I want to be able to click on the ellipse in the canvas and move it to another location in the control itself (ie on the image) 我希望能够单击画布中的椭圆并将其移动到控件本身的另一个位置(即图像上)

For people having the same issue, one possible solution is to implement the draggable object as a Thumb and overriding its DragStarted DragDelta and DragCompleted events. 对于存在相同问题的人们,一种可行的解决方案是将可拖动对象实现为Thumb并覆盖其DragStarted DragDeltaDragCompleted事件。

Here's an example: 这是一个例子:

    private void OnThumbDragDelta(object sender, DragDeltaEventArgs e)
    {
        Thumb thumb = sender as Thumb;

        double newX = Canvas.GetLeft(thumb) + e.HorizontalChange;
        double newY = Canvas.GetTop(thumb) + e.VerticalChange;

            Canvas.SetLeft(thumb, newX);
            Canvas.SetTop(thumb, newY);



        // This is optional for routed events.
        e.RoutedEvent = ThumbDragDeltaEvent;
        RaiseEvent(e);
    }

without using the DragStarted and DragCompleted Events. 而不使用DragStartedDragCompleted事件。

I'd like to see comments on wether this is a preferred solution or if it has any disadvantages. 我希望看到有关这是首选解决方案还是有任何缺点的评论。 From what I can see it's not the most efficient, on fast mouse movements, the thumb movement is delayed and not always "right under the mouse" 从我看到的效果来看,这并不是最有效的,因为鼠标的快速移动会导致拇指移动被延迟,并且并不总是“鼠标正下方”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM