2008-11-16 9 views
16

J'essaie de créer une application WPF dans laquelle je peux faire glisser une image.Glisser une image dans WPF

Actuellement, j'ai une image placée au centre de la fenêtre, et je pense à utiliser les trois mouseevents MouseDown, MouseMove et MouseUp pour calculer la nouvelle position lorsque vous faites glisser l'image.

Y a-t-il d'autres bonnes idées sur la façon de procéder? Je suis totalement nouveau à WPF donc mon état d'esprit est toujours dans le monde Windows Forms. Pour autant que je peux voir, j'ai besoin d'utiliser un afin d'avoir le positionnement absolu disponible.

Répondre

31

ok, voici un « comportement » propriété attachée que vous pouvez utiliser pour faire un élément draggable pourvu qu'il soit sur une toile:

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

} 

Vous pouvez ensuite utiliser dans votre XAML en important l'espace de noms de votre classe est contenue dans (quelque chose comme ça :)

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

Et vous pouvez simplement mettre DraggableExtender.CanDrag = "true" sur des éléments pour faire glisser autour de:

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

Espérons que cela est d'une certaine utilité :)

+2

Merci - code très utile. Je voudrais l'améliorer légèrement en ayant l'élément capturer la souris dans la souris et relâchez la capture de la souris dans la souris. Sinon, il est facile de manquer les mouvements de la souris si, pour une raison quelconque, la souris tombe en dehors des limites de l'objet qui est traîné. –

+0

Bon point - Je viens de faire une chose similaire pour les fenêtres sans chrome, va ajouter cette suggestion;) –

+0

Y at-il un moyen de forcer l'image à glisser uniquement dans la limite de la toile? – Melursus