【问题标题】:Dragging an image in WPF在 WPF 中拖动图像
【发布时间】:2008-11-16 18:52:13
【问题描述】:

我正在尝试创建一个 WPF 应用程序,我可以在其中拖动图像。

目前我在窗口中心放置了一个图像,我正在考虑使用三个鼠标事件 MouseDown、MouseMove 和 MouseUp 来计算拖动图像时的新位置。

关于如何做到这一点,还有其他好主意吗?我对 WPF 完全陌生,所以我的心态仍然在 Windows 窗体世界中。

据我所知,我需要使用 为了获得绝对定位。

【问题讨论】:

    标签: .net wpf user-interface


    【解决方案1】:

    好的,这是一个附加属性“行为”,您可以使用它来使任何元素可拖动,前提是它位于画布上:

    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;
        }
    
    }
    

    然后您可以通过导入您的类所在的命名空间在您的 XAML 中使用它(类似这样:)

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

    然后您可以在要拖动的元素上设置 DraggableExtender.CanDrag="true":

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

    希望这有点用:)

    【讨论】:

    • 谢谢 - 非常有用的代码。我会通过让元素在鼠标向下捕获鼠标并在鼠标向上释放鼠标捕获来稍微改进它。否则,如果由于某种原因鼠标落在被拖动项目的边界之外,很容易错过鼠标移动。
    • 好点 - 我刚刚为无铬窗户做了类似的事情,将添加该建议 ;)
    • 有没有办法强制图像只能在画布限制中拖动?
    【解决方案2】:

    deepcode.co.uk 提供的解决方案是可以的;但是,我在实现它时错过了一些功能,因此我正在扩展他的解决方案。

    当画布内有2个或更多元素时,还需要设置:

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

    这样拖动动作只会影响当前活动的元素。

    人们也可能不希望元素在拖动时超出画布的边界:

        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);
        }
    

    如果您希望活动元素始终显示在顶部:

        private void Element_PreviewMouseDown(object sender, MouseEventArgs e)
        {
            Panel.SetZIndex(element, 1);
        }
    
        private void Element_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            Panel.SetZIndex(element, 0);
        }
    

    【讨论】:

      猜你喜欢
      • 2013-06-06
      • 1970-01-01
      • 2010-12-05
      • 1970-01-01
      • 2013-05-28
      • 1970-01-01
      • 1970-01-01
      • 2013-02-16
      • 2023-04-05
      相关资源
      最近更新 更多