2008-11-16 16 views
16

Estoy tratando de crear una aplicación WPF donde pueda arrastrar una imagen.Arrastrando una imagen en WPF

Actualmente tengo una imagen en el centro de la ventana, y estoy pensando en utilizar los tres eventos de mouse MouseDown, MouseMove y MouseUp para calcular la nueva posición al arrastrar la imagen.

¿Hay alguna otra buena idea sobre cómo hacer esto? Soy totalmente nuevo en WPF, así que mi modo de pensar todavía está en el mundo de Windows Forms.

Por lo que puedo ver, necesito usar un para tener un posicionamiento absoluto disponible.

Respuesta

31

bien, aquí hay un bien embargado "comportamiento" que se puede utilizar para hacer cualquier elemento arrastrable siempre y cuando sea en un lienzo:

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

} 

A continuación, puede utilizar esto en su XAML importando el espacio de nombres de su clase es contenida en (algo como esto :)

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

Y entonces usted puede simplemente establecer DraggableExtender.CanDrag = "true" en elementos de arrastre en torno a:

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

Espero que esto sea de alguna utilidad :)

+2

Gracias - código muy útil. Lo mejoraría ligeramente haciendo que el elemento capture el mouse con el mouse hacia abajo y suelte la captura del mouse con el mouse hacia arriba. De lo contrario, es fácil pasar por alto los movimientos del mouse si por alguna razón el mouse cae fuera de los límites del elemento que se está arrastrando. –

+0

Buen punto: acabo de hacer algo similar para las ventanas sin bordes, agregaré esa sugerencia;) –

+0

¿Hay alguna manera de forzar que la imagen se arrastre solo en el límite del lienzo? – Melursus