Dragging an image in WPF

后端 未结 2 1761
死守一世寂寞
死守一世寂寞 2020-12-01 10:55

I\'m trying to create a WPF application where I can drag an image around.

Currently I have an image placed in the center of the window, and I\'m thinking of using th

相关标签:
2条回答
  • 2020-12-01 11:39

    ok, here's an attached property "behaviour" that you can use to make any element draggable provided it's on a canvas:

    public class DraggableExtender : DependencyObject
    {
        // This is the dependency property we're exposing - we'll 
        // access this as DraggableExtender.CanDrag="true"/"false"
        public static readonly DependencyProperty CanDragProperty =
            DependencyProperty.RegisterAttached("CanDrag",
            typeof(bool),
            typeof(DraggableExtender),
            new UIPropertyMetadata(false, OnChangeCanDragProperty));
    
        // The expected static setter
        public static void SetCanDrag(UIElement element, bool o)
        {
            element.SetValue(CanDragProperty, o);
        }
    
        // the expected static getter
        public static bool GetCanDrag(UIElement element)
        {
            return (bool) element.GetValue(CanDragProperty);
        }
    
        // This is triggered when the CanDrag property is set. We'll
        // simply check the element is a UI element and that it is
        // within a canvas. If it is, we'll hook into the mouse events
        private static void OnChangeCanDragProperty(DependencyObject d, 
                  DependencyPropertyChangedEventArgs e)
        {
            UIElement element = d as UIElement;
            if (element == null) return;
    
            if (e.NewValue != e.OldValue)
            {
                if ((bool)e.NewValue)
                {
                    element.PreviewMouseDown += element_PreviewMouseDown;
                    element.PreviewMouseUp += element_PreviewMouseUp;
                    element.PreviewMouseMove += element_PreviewMouseMove;
                }
                else
                {
                    element.PreviewMouseDown -= element_PreviewMouseDown;
                    element.PreviewMouseUp -= element_PreviewMouseUp;
                    element.PreviewMouseMove -= element_PreviewMouseMove;
                }
            }
        }
    
        // Determine if we're presently dragging
        private static bool _isDragging = false;
        // The offset from the top, left of the item being dragged 
        // and the original mouse down
        private static Point _offset;
    
        // This is triggered when the mouse button is pressed 
        // on the element being hooked
        static void element_PreviewMouseDown(object sender,
                System.Windows.Input.MouseButtonEventArgs e)
        {
            // Ensure it's a framework element as we'll need to 
            // get access to the visual tree
            FrameworkElement element = sender as FrameworkElement;
            if (element == null) return;
    
            // start dragging and get the offset of the mouse 
            // relative to the element
            _isDragging = true;
            _offset = e.GetPosition(element);
        }
    
        // This is triggered when the mouse is moved over the element
        private static void element_PreviewMouseMove(object sender, 
                  MouseEventArgs e)
        {
            // If we're not dragging, don't bother - also validate the element
            if (!_isDragging) return;
    
            FrameworkElement element = sender as FrameworkElement;
            if (element == null) return;
    
            Canvas canvas = element.Parent as Canvas;
            if( canvas == null ) return;
    
            // Get the position of the mouse relative to the canvas
            Point mousePoint = e.GetPosition(canvas);
    
            // Offset the mouse position by the original offset position
            mousePoint.Offset(-_offset.X, -_offset.Y);
    
            // Move the element on the canvas
            element.SetValue(Canvas.LeftProperty, mousePoint.X);
            element.SetValue(Canvas.TopProperty, mousePoint.Y);
        }
    
        // this is triggered when the mouse is released
        private static void element_PreviewMouseUp(object sender, 
                MouseButtonEventArgs e)
        {
            _isDragging = false;
        }
    
    }
    

    You can then use this in your XAML by importing the namespace your class is contained in (something like this:)

    <Window x:Class="WPFFunWithDragging.Window1"
            xmlns:local="clr-namespace:WPFFunWithDragging" .. >
    

    And then you can just set DraggableExtender.CanDrag="true" on elements to drag around:

    <Canvas>
        <Image Source="Garden.jpg" 
               Width="50" 
               Canvas.Left="10" Canvas.Top="10" 
               local:DraggableExtender.CanDrag="true"/>
    </Canvas>
    

    Hope this is of some use :)

    0 讨论(0)
  • 2020-12-01 11:46

    The solution that deepcode.co.uk provided is ok; however, I missed some functonalities when imlementing it, therefore I'm expanding on his solution.

    When there are 2 or more elements within the canvas, it is necessary to also set:

        private void Element_PreviewMouseDown(object sender, MouseEventArgs e)
        {
            element.CaptureMouse();
        }
    
        private void Element_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            element.ReleaseMouseCapture();
        }
    

    So that the dragging action would influence only the currently active element.

    One may also not want an element to go beyond the borders of the canvas when dragging:

        if (mousePoint.X > 0 && mousePoint.X + element.ActualWidth <= canvas.ActualWidth &&
            mousePoint.Y > 0 && mousePoint.Y + element.ActualHeight <= canvas.ActualHeight)
        {
            element.SetValue(Canvas.LeftProperty, mousePoint.X);
            element.SetValue(Canvas.TopProperty, mousePoint.Y);
        }
    

    And in case you want the active element to always appear on top:

        private void Element_PreviewMouseDown(object sender, MouseEventArgs e)
        {
            Panel.SetZIndex(element, 1);
        }
    
        private void Element_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            Panel.SetZIndex(element, 0);
        }
    
    0 讨论(0)
提交回复
热议问题