2014-05-08 69 views
2

我在尋找允許用戶順暢地拖動網格控件周圍的自定義控件,但我不確定我缺少的是什麼。所有控件都有AllowDrop設置爲true。將自定義控件拖放到網格上

  1. MouseMove我做正在拖動控制如下:

    DataObject dataObj = new DataObject("PersistentObject",this); 
    DragDrop.DoDragDrop(this, dataObj, DragDropEffects.Move); 
    
  2. 對電網的DragEnterDragOver,並且DragDrop事件,我設置了DragEventArg所有的效果。

反饋顯示它在網格上的新位置是一個有效的放置目標,但似乎從未移動。

有沒有辦法在網格上做到這一點,或者我試圖在錯誤的控制上做到這一點(我使用網格,因爲設計師從一開始)?

是否還有其他需要修復的事件,和/或我現有的事件是否被破壞?

編輯:它也將被讚賞,如果它顯示控件被拖動,因爲它正在發生。我不確定這是否應該發生在我目前的做法,但這是目標。

回答

2

您可以輕鬆地做到這一點使用內置的拖放的東西。

Point mouseOffset = new Point(); 

userControl.PreviewMouseLeftButtonDown += (sender, e) => 
{ 
    mouseOffset = Mouse.GetPosition(userControl); 
    userControl.CaptureMouse(); 
}; 

userControl.PreviewMouseMove += (sender, e) => 
{ 
    if (userControl.IsMouseCaptured) 
    { 
     Point mouseDelta = Mouse.GetPosition(userControl); 
     mouseDelta.Offset(-mouseOffset.X, -mouseOffset.Y); 

     userControl.Margin = new Thickness(
      userControl.Margin.Left + mouseDelta.X, 
      userControl.Margin.Top + mouseDelta.Y, 
      userControl.Margin.Right - mouseDelta.X, 
      userControl.Margin.Bottom - mouseDelta.Y); 
    } 
}; 

userControl.PreviewMouseLeftButtonUp += (sender, e) => 
{ 
    userControl.ReleaseMouseCapture(); 
}; 

所以我寫了這個演示代碼看起來像下面這樣:

<Window x:Class="StackOverflowScratchpad.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="350" 
    Width="525"> 
    <Grid> 
     <!-- I am using a Button here just for simplicity. The code 
      will function the same no matter what control is used. --> 
     <Button x:Name="userControl" Width="75" Height="23" /> 
    </Grid> 
</Window> 

public MainWindow() 
{ 
    InitializeComponent(); 

    Loaded += MainWindow_Loaded; 
} 

private void MainWindow_Loaded(object obj, RoutedEventArgs args) 
{ 
    // Add the above C# here. 
} 
+0

我嘗試過(我把這段代碼放在控件視圖的加載方法中,然後把控件放在畫布上),但它似乎沒有工作。想法出了什麼問題? – soandos

+0

@soandos我以爲你在使用'Grid'。如果您使用'Canvas',則可以使用'Canvas.SetLeft'和'Canvas.SetTop'替換'userControl.Margin'行。 –

+0

所以很清楚,這是我的自定義控件onload,還是在canvas onload? – soandos

0

你必須處理的代碼自己的投遞事件

Drop事件當一個對象的元素被用作放置目標的範圍之內下降時發生。

private void grid_Drop(object sender, DragEventArgs eventarg) 
{ 
    // check data is present returns a bool 
if (eventarg.Data.GetDataPresent("PersistentObject")) 
      { 
       var yourdata=eventarg.Data.GetData("PersistentObject")as Model(T) ; 
       if (yourdata!= null) 
       { 
        // add to gird or whatever. 
        // place the object as you desire 
       } 

} 

一些將&降Reference

+0

是一個網格,這個正確的控制?我怎樣才能爲網格上的控件設置正確的位置(同樣,這應該是光滑的,而不是離散的?是不是應該是自動的? – soandos

+0

取決於你放下的東西。關於我斜紋的位置是動態排列的,所以如果你想設置一個模式,可以根據你的需要設置一個堆棧面板設置的方向,並設置填充等等,或者如果你願意,你可以在網格上添加對象到列上的放置事件本身 – Eldho

+0

我想要的位置如果我需要使用一個堆疊面板,我應該改變什麼? – soandos

1

我會建議使用Canvas控件來代替。這裏是一個Canvas控件的例子,你放入的任何東西都可以讓用戶拖動以及調整大小:

不是原始代碼不是我的,雖然我已經做了一些修改,這是我發現在網上。 (很想引用這裏的消息來源,但很久很久以來我就被遺忘了。)

希望這會有所幫助,或者至少可以指引您尋找正確的方向。

SuperCanvas:

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Input; 
using Meld.Helpers; 

namespace Meld.Controls 
{ 
    public class SuperCanvas : Canvas 
    { 
     private AdornerLayer aLayer; 

     private bool isDown; 
     private bool isDragging; 
     private double originalLeft; 
     private double originalTop; 
     private bool selected; 
     private UIElement selectedElement; 

     private Point startPoint; 

     private bool locked; 

     public SuperCanvas() 
     { 
      Loaded += OnLoaded; 
     } 

     private void OnLoaded(object sender, RoutedEventArgs e) 
     { 
      MouseLeftButtonDown += WorkspaceWindow_MouseLeftButtonDown; 
      MouseLeftButtonUp += DragFinishedMouseHandler; 
      MouseMove += WorkspaceWindow_MouseMove; 
      MouseLeave += Window1_MouseLeave; 

      PreviewMouseLeftButtonDown += myCanvas_PreviewMouseLeftButtonDown; 
      PreviewMouseLeftButtonUp += DragFinishedMouseHandler; 
     } 

     // Handler for drag stopping on leaving the window 
     private void Window1_MouseLeave(object sender, MouseEventArgs e) 
     { 
      StopDragging(); 
      e.Handled = true; 
     } 

     // Handler for drag stopping on user choice 
     private void DragFinishedMouseHandler(object sender, MouseButtonEventArgs e) 
     { 
      StopDragging(); 
      e.Handled = true; 
     } 

     // Method for stopping dragging 
     private void StopDragging() 
     { 
      if (isDown) 
      { 
       isDown = false; 
       isDragging = false; 
      } 
     } 

     // Hanler for providing drag operation with selected element 
     private void WorkspaceWindow_MouseMove(object sender, MouseEventArgs e) 
     { 
      if (locked) return; 

      if (isDown) 
      { 
       if ((isDragging == false) && 
        ((Math.Abs(e.GetPosition(this).X - startPoint.X) > 
         SystemParameters.MinimumHorizontalDragDistance) || 
        (Math.Abs(e.GetPosition(this).Y - startPoint.Y) > SystemParameters.MinimumVerticalDragDistance))) 
        isDragging = true; 

       if (isDragging) 
       { 
        Point position = Mouse.GetPosition(this); 
        SetTop(selectedElement, position.Y - (startPoint.Y - originalTop)); 
        SetLeft(selectedElement, position.X - (startPoint.X - originalLeft)); 
       } 
      } 
     } 

     // Handler for clearing element selection, adorner removal 
     private void WorkspaceWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
     { 
      if (locked) return; 

      if (selected) 
      { 
       selected = false; 
       if (selectedElement != null) 
       { 
        aLayer.Remove(aLayer.GetAdorners(selectedElement)[0]); 
        selectedElement = null; 
       } 
      } 
     } 

     // Handler for element selection on the canvas providing resizing adorner 
     private void myCanvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
     { 
      //add code to lock dragging and dropping things. 
      if (locked) 
      { 
       e.Handled = true; 
       return; 
      } 

      // Remove selection on clicking anywhere the window 
      if (selected) 
      { 
       selected = false; 
       if (selectedElement != null) 
       { 
        // Remove the adorner from the selected element 
        aLayer.Remove(aLayer.GetAdorners(selectedElement)[0]); 
        selectedElement = null; 
       } 
      } 

      // If any element except canvas is clicked, 
      // assign the selected element and add the adorner 
      if (e.Source != this) 
      { 
       isDown = true; 
       startPoint = e.GetPosition(this); 

       selectedElement = e.Source as UIElement; 

       originalLeft = GetLeft(selectedElement); 
       originalTop = GetTop(selectedElement); 

       aLayer = AdornerLayer.GetAdornerLayer(selectedElement); 
       aLayer.Add(new ResizingAdorner(selectedElement)); 
       selected = true; 
       e.Handled = true; 
      } 
     } 
    } 
} 

而且ResizingAdorner:

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Controls.Primitives; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 

namespace Meld.Helpers 
{ 
    internal class ResizingAdorner : Adorner 
    { 
     // Resizing adorner uses Thumbs for visual elements. 
     // The Thumbs have built-in mouse input handling. 
     Thumb topLeft, topRight, bottomLeft, bottomRight; 

     // To store and manage the adorner's visual children. 
     VisualCollection visualChildren; 

     // Initialize the ResizingAdorner. 
     public ResizingAdorner(UIElement adornedElement) : base(adornedElement) 
     {     
      visualChildren = new VisualCollection(this); 

      // Call a helper method to initialize the Thumbs 
      // with a customized cursors. 
      BuildAdornerCorner(ref topLeft, Cursors.SizeNWSE); 
      BuildAdornerCorner(ref topRight, Cursors.SizeNESW); 
      BuildAdornerCorner(ref bottomLeft, Cursors.SizeNESW); 
      BuildAdornerCorner(ref bottomRight, Cursors.SizeNWSE); 

      // Add handlers for resizing. 
      bottomLeft.DragDelta += new DragDeltaEventHandler(HandleBottomLeft); 
      bottomRight.DragDelta += new DragDeltaEventHandler(HandleBottomRight); 
      topLeft.DragDelta += new DragDeltaEventHandler(HandleTopLeft); 
      topRight.DragDelta += new DragDeltaEventHandler(HandleTopRight); 
     } 

     // Handler for resizing from the bottom-right. 
     void HandleBottomRight(object sender, DragDeltaEventArgs args) 
     { 
      FrameworkElement adornedElement = this.AdornedElement as FrameworkElement; 
      Thumb hitThumb = sender as Thumb; 

      if (adornedElement == null || hitThumb == null) return; 
      FrameworkElement parentElement = adornedElement.Parent as FrameworkElement; 

      // Ensure that the Width and Height are properly initialized after the resize. 
      EnforceSize(adornedElement); 

      // Change the size by the amount the user drags the mouse, as long as it's larger 
      // than the width or height of an adorner, respectively. 
      adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width); 
      adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height); 
     } 

     // Handler for resizing from the top-right. 
     void HandleTopRight(object sender, DragDeltaEventArgs args) 
     { 
      FrameworkElement adornedElement = this.AdornedElement as FrameworkElement; 
      Thumb hitThumb = sender as Thumb; 

      if (adornedElement == null || hitThumb == null) return; 
      FrameworkElement parentElement = adornedElement.Parent as FrameworkElement; 

      // Ensure that the Width and Height are properly initialized after the resize. 
      EnforceSize(adornedElement); 

      // Change the size by the amount the user drags the mouse, as long as it's larger 
      // than the width or height of an adorner, respectively. 
      adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width); 
      //adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height); 

      double height_old = adornedElement.Height; 
      double height_new = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height); 
      double top_old = Canvas.GetTop(adornedElement); 
      adornedElement.Height = height_new; 
      Canvas.SetTop(adornedElement, top_old - (height_new - height_old)); 
     } 

     // Handler for resizing from the top-left. 
     void HandleTopLeft(object sender, DragDeltaEventArgs args) 
     { 
      FrameworkElement adornedElement = AdornedElement as FrameworkElement; 
      Thumb hitThumb = sender as Thumb; 

      if (adornedElement == null || hitThumb == null) return; 

      // Ensure that the Width and Height are properly initialized after the resize. 
      EnforceSize(adornedElement); 

      // Change the size by the amount the user drags the mouse, as long as it's larger 
      // than the width or height of an adorner, respectively. 
      //adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width); 
      //adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height); 

      double width_old = adornedElement.Width; 
      double width_new = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width); 
      double left_old = Canvas.GetLeft(adornedElement); 
      adornedElement.Width = width_new; 
      Canvas.SetLeft(adornedElement, left_old - (width_new - width_old)); 

      double height_old = adornedElement.Height; 
      double height_new = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height); 
      double top_old = Canvas.GetTop(adornedElement); 
      adornedElement.Height = height_new; 
      Canvas.SetTop(adornedElement, top_old - (height_new - height_old)); 
     } 

     // Handler for resizing from the bottom-left. 
     void HandleBottomLeft(object sender, DragDeltaEventArgs args) 
     { 
      FrameworkElement adornedElement = AdornedElement as FrameworkElement; 
      Thumb hitThumb = sender as Thumb; 

      if (adornedElement == null || hitThumb == null) return; 

      // Ensure that the Width and Height are properly initialized after the resize. 
      EnforceSize(adornedElement); 

      // Change the size by the amount the user drags the mouse, as long as it's larger 
      // than the width or height of an adorner, respectively. 
      //adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width); 
      adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height); 

      double width_old = adornedElement.Width; 
      double width_new = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width); 
      double left_old = Canvas.GetLeft(adornedElement); 
      adornedElement.Width = width_new;    
      Canvas.SetLeft(adornedElement, left_old - (width_new - width_old)); 
     } 

     // Arrange the Adorners. 
     protected override Size ArrangeOverride(Size finalSize) 
     { 
      // desiredWidth and desiredHeight are the width and height of the element that's being adorned. 
      // These will be used to place the ResizingAdorner at the corners of the adorned element. 
      double desiredWidth = AdornedElement.DesiredSize.Width; 
      double desiredHeight = AdornedElement.DesiredSize.Height; 
      // adornerWidth & adornerHeight are used for placement as well. 
      double adornerWidth = this.DesiredSize.Width; 
      double adornerHeight = this.DesiredSize.Height; 

      topLeft.Arrange(new Rect(-adornerWidth/2, -adornerHeight/2, adornerWidth, adornerHeight)); 
      topRight.Arrange(new Rect(desiredWidth - adornerWidth/2, -adornerHeight/2, adornerWidth, adornerHeight)); 
      bottomLeft.Arrange(new Rect(-adornerWidth/2, desiredHeight - adornerHeight/2, adornerWidth, adornerHeight)); 
      bottomRight.Arrange(new Rect(desiredWidth - adornerWidth/2, desiredHeight - adornerHeight/2, adornerWidth, adornerHeight)); 

      // Return the final size. 
      return finalSize; 
     } 

     // Helper method to instantiate the corner Thumbs, set the Cursor property, 
     // set some appearance properties, and add the elements to the visual tree. 
     void BuildAdornerCorner(ref Thumb cornerThumb, Cursor customizedCursor) 
     { 
      if (cornerThumb != null) return; 

      cornerThumb = new Thumb(); 

      // Set some arbitrary visual characteristics. 
      cornerThumb.Cursor = customizedCursor; 
      cornerThumb.Height = cornerThumb.Width = 5; 
      cornerThumb.Opacity = 0.40; 
      cornerThumb.Background = new SolidColorBrush(Colors.White); 

      visualChildren.Add(cornerThumb); 
     } 

     // This method ensures that the Widths and Heights are initialized. Sizing to content produces 
     // Width and Height values of Double.NaN. Because this Adorner explicitly resizes, the Width and Height 
     // need to be set first. It also sets the maximum size of the adorned element. 
     void EnforceSize(FrameworkElement adornedElement) 
     { 
      if (adornedElement.Width.Equals(Double.NaN)) 
       adornedElement.Width = adornedElement.DesiredSize.Width; 
      if (adornedElement.Height.Equals(Double.NaN)) 
       adornedElement.Height = adornedElement.DesiredSize.Height; 

      FrameworkElement parent = adornedElement.Parent as FrameworkElement; 
      if (parent != null) 
      { 
       adornedElement.MaxHeight = parent.ActualHeight; 
       adornedElement.MaxWidth = parent.ActualWidth; 
      } 
     } 
     // Override the VisualChildrenCount and GetVisualChild properties to interface with 
     // the adorner's visual collection. 
     protected override int VisualChildrenCount { get { return visualChildren.Count; } } 
     protected override Visual GetVisualChild(int index) { return visualChildren[index]; } 
    } 
} 
+0

您可以將內容添加到「Meld.Helpers」嗎?我似乎無法在任何地方找到它,並且樣本沒有它就不能編譯。 – soandos

0

我創建了一個DragDropBehaviour類幾年前。你應該能夠複製粘貼它並且改變OnDrop功能。

public static class DragDropBehaviour 
{ 
    #region CanDrag attached dependancy property 
    /// <summary> 
    /// The CanDrag attached property'str name. 
    /// </summary> 
    public const string CanDragPropertyName = "CanDrag"; 

    /// <summary> 
    /// Gets the value of the CanDrag attached property 
    /// for a given dependency object. 
    /// </summary> 
    /// <param name="obj">The object for which the property value 
    /// is read.</param> 
    /// <returns>The value of the CanDrag property of the specified object.</returns> 
    public static bool GetCanDrag(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(CanDragProperty); 
    } 

    /// <summary> 
    /// Sets the value of the CanDrag attached property 
    /// for a given dependency object. 
    /// </summary> 
    /// <param name="obj">The object to which the property value 
    /// is written.</param> 
    /// <param name="value">Sets the CanDrag value of the specified object.</param> 
    public static void SetCanDrag(DependencyObject obj, bool value) 
    { 
     obj.SetValue(CanDragProperty, value); 
    } 

    /// <summary> 
    /// Identifies the CanDrag attached property. 
    /// </summary> 
    public static readonly DependencyProperty CanDragProperty = DependencyProperty.RegisterAttached(
     CanDragPropertyName, 
     typeof(bool), 
     typeof(DragDropBehaviour), 
     new UIPropertyMetadata(false, OnCanDragChanged)); 
    #endregion 

    #region CanDrop attached dependancy property 
    /// <summary> 
    /// The CanDrop attached property'str name. 
    /// </summary> 
    public const string CanDropPropertyName = "CanDrop"; 

    /// <summary> 
    /// Gets the value of the CanDrop attached property 
    /// for a given dependency object. 
    /// </summary> 
    /// <param name="obj">The object for which the property value 
    /// is read.</param> 
    /// <returns>The value of the CanDrop property of the specified object.</returns> 
    public static bool GetCanDrop(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(CanDropProperty); 
    } 

    /// <summary> 
    /// Sets the value of the CanDrop attached property 
    /// for a given dependency object. 
    /// </summary> 
    /// <param name="obj">The object to which the property value 
    /// is written.</param> 
    /// <param name="value">Sets the CanDrop value of the specified object.</param> 
    public static void SetCanDrop(DependencyObject obj, bool value) 
    { 
     obj.SetValue(CanDropProperty, value); 
    } 

    /// <summary> 
    /// Identifies the CanDrop attached property. 
    /// </summary> 
    public static readonly DependencyProperty CanDropProperty = DependencyProperty.RegisterAttached(
     CanDropPropertyName, 
     typeof(bool), 
     typeof(DragDropBehaviour), 
     new UIPropertyMetadata(false, OnCanDropChanged)); 
    #endregion 

    #region DragDropAction attached dependancy property 
    /// <summary> 
    /// The DragDropAction attached property'str name. 
    /// </summary> 
    public const string DragDropActionPropertyName = "DragDropAction"; 

    /// <summary> 
    /// Gets the value of the DragDropAction attached property 
    /// for a given dependency object. 
    /// </summary> 
    /// <param name="obj">The object for which the property value 
    /// is read.</param> 
    /// <returns>The value of the DragDropAction property of the specified object.</returns> 
    public static DragDropAction GetDragDropAction(DependencyObject obj) 
    { 
     return (DragDropAction)obj.GetValue(DragDropActionProperty); 
    } 

    /// <summary> 
    /// Sets the value of the DragDropAction attached property 
    /// for a given dependency object. 
    /// </summary> 
    /// <param name="obj">The object to which the property value 
    /// is written.</param> 
    /// <param name="value">Sets the DragDropAction value of the specified object.</param> 
    public static void SetDragDropAction(DependencyObject obj, DragDropAction value) 
    { 
     obj.SetValue(DragDropActionProperty, value); 
    } 

    /// <summary> 
    /// Identifies the DragDropAction attached property. 
    /// </summary> 
    public static readonly DependencyProperty DragDropActionProperty = DependencyProperty.RegisterAttached(
     DragDropActionPropertyName, 
     typeof(DragDropAction), 
     typeof(DragDropBehaviour), 
     new UIPropertyMetadata(null)); 
    #endregion 

    static void OnCanDragChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e) 
    { 
     FrameworkElement element = depObj as FrameworkElement; 

     if (element != null) 
     { 
      if ((bool)e.NewValue) 
      { 
       GetOrCreateAction(depObj).DragBehaviour(element, true); 
      } 
      else 
      { 
       GetOrCreateAction(depObj).DragBehaviour(element, false);      
      } 
     } 
    } 

    static void OnCanDropChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e) 
    { 
     FrameworkElement element = depObj as FrameworkElement; 

     if (element != null) 
     { 
      if ((bool)e.NewValue) 
      { 
       GetOrCreateAction(depObj).DropBehaviour(element, true); 
      } 
      else 
      { 
       GetOrCreateAction(depObj).DropBehaviour(element, false); 
      } 
     } 
    } 

    static DragDropAction GetOrCreateAction(DependencyObject depObj) 
    { 
     DragDropAction action = depObj.GetValue(DragDropActionProperty) as DragDropAction; 
     if (action == null) 
     { 
      action = new DragDropAction(); 
      depObj.SetValue(DragDropActionProperty, action); 
     } 
     return action; 
    } 
} 

public class DragDropAction 
{ 
    Point _start; 
    FrameworkElement _dragged; 

    public void DragBehaviour(FrameworkElement element, bool enable) 
    { 
     if (enable) 
     { 
      element.PreviewMouseLeftButtonDown += OnPreviewMouseLeftButtonDown; 
      element.PreviewMouseMove += OnPreviewMouseMove; 
     } 
     else 
     { 
      element.PreviewMouseLeftButtonDown -= OnPreviewMouseLeftButtonDown; 
      element.PreviewMouseMove -= OnPreviewMouseMove; 
     } 
    } 

    public void DropBehaviour(FrameworkElement element, bool enable) 
    { 
     if (enable) 
     { 
      element.Drop += OnDrop; 
      element.AllowDrop = true; 
     } 
     else 
     { 
      element.Drop -= OnDrop; 
      element.AllowDrop = false; 
     } 
    } 

    void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
    { 
     FrameworkElement element = sender as FrameworkElement; 
     if (element != null) 
     { 
      int[] position = Win32Mouse.GetMousePosition(); 
      _start = new Point(position[0], position[1]); 
      _dragged = element; 
     } 
    } 

    void OnPreviewMouseMove(object sender, MouseEventArgs e) 
    { 
     FrameworkElement element = sender as FrameworkElement; 
     if (element != null && _dragged != null) 
     { 
      int[] position = Win32Mouse.GetMousePosition(); 
      Point currentPosition = new Point(position[0], position[1]); 
      Vector diff = _start - currentPosition; 

      if (e.LeftButton == MouseButtonState.Pressed && 
       Math.Abs(diff.X) > (SystemParameters.MinimumHorizontalDragDistance) && 
       Math.Abs(diff.Y) > (SystemParameters.MinimumVerticalDragDistance)) 
      { 
       DragDropEffects effects = DragDrop.DoDragDrop(element, _dragged.DataContext, DragDropEffects.Move); 
       _dragged = null; 
       e.Handled = true; 
      } 
     } 
    } 

    void OnDrop(object sender, DragEventArgs e) 
    { 
     FrameworkElement element = sender as FrameworkElement; 
     if (element != null) 
     { 
      TabViewModel tab = element.DataContext as TabViewModel; 
      if (tab == null) 
      { 
       // TabViewModel not found it element, it's possible that the drop was done on the lastOpened 'Canvas' element. 
       var tabControls = element.FindVisualChildren<TabControl>(); 
       var menus = element.FindVisualChildren<Menu>(); 
       var itemControls = element.FindVisualChildren<ItemsControl>(); 

       if (tabControls.Count > 0 && tabControls[0].Visibility == Visibility.Visible) 
       { 
        // If currently in 'horizontal mode' add to the active tab. If there is no active tab 
        // just add to the bottom tab. 
        tab = tabControls[0].SelectedItem as TabViewModel; 
        if (tab == null)       
         tab = tabControls[0].Items.GetItemAt(tabControls[0].Items.Count - 1) as TabViewModel;       
       } 
       else if (menus.Count > 0 && menus[0].Visibility == Visibility.Visible) 
       { 
        // If currently in 'vertical mode' add to the default tab, there is no 'active' menu item after all. 
        var tabs = menus[0].Items.SourceCollection as ObservableCollection<TabViewModel>; 
        tab = tabs.SingleOrDefault(obj => obj.Title == Configuration.DefaultTab) ?? tabs.LastOrDefault(); 
       } 
       else if (itemControls.Count > 0 && itemControls[0].Visibility == Visibility.Visible) 
       { 
        var window = element.FindVisualParent<Window>(); 
        if (window != null && window.DataContext is MainViewModel) 
        { 
         // Add the currently expanded tab. 
         MainViewModel mainViewModel = (MainViewModel)window.DataContext; 
         tab = mainViewModel.ExpandedTab; 

         // If no tab is expanded, add to the default tab or the bottom tab. 
         if (tab == null) 
         { 
          tab = mainViewModel.Tabs.SingleOrDefault(obj => obj.Title == Configuration.DefaultTab) 
            ?? mainViewModel.Tabs.LastOrDefault(); 
         } 
        } 
       } 
      } 

      if (tab != null) 
      { 
       if (e.Data.GetDataPresent(DataFormats.FileDrop)) 
       {       
        DispatcherHelper.UIDispatcher.BeginInvoke(new Action(() => 
         { 
          string[] droppedFilePaths = e.Data.GetData(DataFormats.FileDrop, true) as string[]; 
          foreach (string fileName in droppedFilePaths) 
          { 
           try 
           { 

            ApplicationModel model = ApplicationModel.FromFile(fileName, tab.Title); 
            ApplicationViewModel application = new ApplicationViewModel(model); 
            Messenger.Default.Send<ApplicationMessage>(ApplicationMessage.Add(application, tab)); 
           } 
           catch (FileNotFoundException ex) 
           { 
            ServiceManager.GetService<IMessageBoxService>().Show(
             "Could not add application - " + ex.Message, "Astounding Dock", MessageIcon.Error); 
           } 
          } 
         })); 
        e.Handled = true; 
       } 
       else if (e.Data.GetDataPresent<ApplicationViewModel>()) 
       { 
        DispatcherHelper.UIDispatcher.BeginInvoke(new Action(() => 
         { 
          ApplicationViewModel application = e.Data.GetData<ApplicationViewModel>(); 
          Messenger.Default.Send<ApplicationMessage>(ApplicationMessage.Move(application, tab)); 
         })); 
        e.Handled = true; 
       } 
       else 
       { 
        Debug.WriteLine("DragDropBehaviour: Unknown data droppped - " + String.Join(",", e.Data.GetFormats())); 
       } 
      } 
     } 
    } 
} 

https://github.com/notsonormal/AstoundingDock/blob/master/src/AstoundingDock/Ui/DragDropBehaviour.cs

您可以啓用未落像

<Canvas ui:DragDropBehaviour.CanDrop="True"> 
</Canvas> 

一個控制功能,可拖放這樣

<Button ui:DragDropBehaviour.CanDrag="True" ui:DragDropBehaviour.CanDrop="True"> 
</Button> 

https://github.com/notsonormal/AstoundingDock/blob/master/src/AstoundingDock/Views/MainWindow.xaml

似乎很普通,但我只用它爲一個特定的情況下,所以...