private bool CanExecuteDrag(DragCommandParameter parameter)
        {
            // Determine the data that is dragged and store it in parameter.Tag.
            // If a ContentControl is dragged, use ContentControl.Content.
            var contentControl = AssociatedObject as ContentControl;

            if (contentControl != null)
            {
                // The dragged element is not within an ItemsControl.
                // --> Select the data-context.
                parameter.Tag = contentControl.Content;
                return(true);
            }

            // If an item of an ItemsControl is dragged, use ItemContainer.DataContext.
            var itemsControl = AssociatedObject as ItemsControl;

            if (itemsControl != null)
            {
                // The dragged element is within an ItemsControl.
                // --> Select the clicked item.
                var visual = parameter.HitObject as Visual;
                Debug.Assert(visual != null, "HitObject should always be set.");
                var itemContainer = itemsControl.ContainerFromElement(visual) as FrameworkElement;
                if (itemContainer != null)
                {
                    parameter.Tag = itemContainer.DataContext;
                    return(true);
                }
            }

            return(false);
        }
        private void DisableDrag()
        {
            // Abort current drag operation.
            _dragCommandParameter = null;

            // Unregister event handlers.
            AssociatedObject.PreviewMouseLeftButtonDown -= OnPreviewMouseLeftButtonDown;
            AssociatedObject.MouseLeftButtonDown        -= OnMouseLeftButtonDown;
            AssociatedObject.PreviewMouseLeftButtonUp   -= OnPreviewMouseLeftButtonUp;
            AssociatedObject.PreviewMouseMove           -= OnPreviewMouseMove;
        }
        private void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs eventArgs)
        {
            if (eventArgs.Handled || !UsePreviewEvent)
            {
                return;
            }

            _dragCommandParameter = new DragCommandParameter
            {
                AssociatedObject = AssociatedObject,
                HitObject        = eventArgs.OriginalSource as DependencyObject,
                MousePosition    = eventArgs.GetPosition(AssociatedObject),
            };

            OnMouseLeftButtonDown(eventArgs);
        }
        private void OnPreviewMouseMove(object sender, MouseEventArgs eventArgs)
        {
            if (eventArgs.Handled)
            {
                return;
            }

            if (_dragCommandParameter == null)
            {
                return;
            }

            // Avoid reentrance
            if (_inDragDrop)
            {
                // Not sure why this happens. It can happen when dragging from a Button...
                return;
            }

            // Only start drag-and-drop when user moved the mouse by a reasonable amount.
            if (!ExceedsMinimumDragDistance(_dragCommandParameter.MousePosition, eventArgs.GetPosition(AssociatedObject)))
            {
                return;
            }

            _inDragDrop = true;

            // The user wants to drag something.
            try
            {
                var dragCommand = DragCommand ?? DefaultDragCommand;
                if (dragCommand.CanExecute(_dragCommandParameter))
                {
                    // Call DragCommand to start the drag-and-drop operation.
                    dragCommand.Execute(_dragCommandParameter);
                    eventArgs.Handled = true;
                }
            }
            finally
            {
                _inDragDrop           = false;
                _dragCommandParameter = null;
            }
        }
        private void OnMouseLeftButtonDown(MouseButtonEventArgs eventArgs)
        {
            _dragCommandParameter = new DragCommandParameter
            {
                AssociatedObject = AssociatedObject,
                HitObject        = eventArgs.OriginalSource as DependencyObject,
                MousePosition    = eventArgs.GetPosition(AssociatedObject),
            };

            // Call DragCommand.CanExecute() and let the view model decide whether
            // dragging is possible. The drag-and-drop starts in the mouse move
            // event when the user moves the mouse by a significant distance.
            var dragCommand = DragCommand ?? DefaultDragCommand;

            if (!dragCommand.CanExecute(_dragCommandParameter))
            {
                _dragCommandParameter = null;
            }
        }
        private void ExecuteDrag(DragCommandParameter parameter)
        {
            // The data was determined in CanExecuteDrag and stored in the Tag.
            var data = parameter.Tag;

            if (data == null)
            {
                return;
            }

            // Wrap data in IDataObject.
            var dataObject = SetData(data);

            _sourceUpdated = false;

            // Execute drag-and-drop.
            var effect = DragDrop.DoDragDrop(parameter.AssociatedObject, dataObject, DefaultEffects);

            // Update source if not already handled by DropCommand.
            if ((effect & DragDropEffects.Move) != 0 && !_sourceUpdated)
            {
                // Remove data from source.
                var contentControl = parameter.AssociatedObject as ContentControl;
                var itemsControl   = parameter.AssociatedObject as ItemsControl;
                if (contentControl != null)
                {
                    // Source is a ContentControl.
                    // --> Remove content.
                    contentControl.Content = null;
                }
                else if (itemsControl != null)
                {
                    // Source is an ItemsControl.
                    // --> Remove item.
                    RemoveItemFromItemsControl(itemsControl, data);
                }
            }
        }
 private void OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs eventArgs)
 {
     // Cancel drag operation.
     _dragCommandParameter = null;
 }