简体   繁体   中英

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. 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.

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.

Update 1: To address comments, here is some code:

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

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.

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.

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"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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