Question

I am looking to allow a user to drag a custom control around a Grid control smoothly, and I am not sure exactly what I am missing. All controls have AllowDrop set to true.

  1. On MouseMove I do the following in the control that is being dragged:

    DataObject dataObj = new DataObject("PersistentObject",this);
    DragDrop.DoDragDrop(this, dataObj, DragDropEffects.Move);
    
  2. On the Grid's DragEnter, DragOver, and DragDrop events, I set the effects of the DragEventArg to all.

The feedback shows that it the new location on the grid is a valid drop target, but it never seems to move.

Is there a way to do this on a Grid, or I am trying to do this on the wrong control (I am using a grid because the designer started with one)?

Are there other events that I have to fix, and/or are my current ones broken?

Edit: It would also be appreciated if it showed the control being dragged as it was happening. I am not sure if that is supposed to happen with my current approach, but that is the goal.

Was it helpful?

Solution

You can easily do this without using the built-in drag-drop stuff.

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

So the demo code I wrote up for this looks something like the following:

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

OTHER TIPS

I would suggest using a Canvas control instead. Here is an example Canvas control that anything you put in it will allow the user to drag around as well as resize:

Not the original code is NOT mine, although I have done some modifications to it, this was something I found on the web. (would love to quote the source here but I've long since forgotten unfortunately.)

Hopefully this helps, or at least points you in the right direction for what your looking for.

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

And the 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]; }
    }
}

you have to handle the code own Drop event

Drop event Occurs when an object is dropped within the bounds of an element that is acting as a drop target.

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
                }

 }   

Some Drag&Drop Reference

I created a DragDropBehaviour class a few years back. You should be able to copy-paste it and just change the OnDrop function.

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

You can enable dropping on a control like

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

And enable dragging and dropping like this

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

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

It seems pretty generic but I only ever used it for one specific case so...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top