Skip to content

Instantly share code, notes, and snippets.

@JannikArndt
Created May 10, 2014 11:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JannikArndt/7c2fc2eb998bf2ffc89f to your computer and use it in GitHub Desktop.
Save JannikArndt/7c2fc2eb998bf2ffc89f to your computer and use it in GitHub Desktop.
Custom Drag and Drop with multiple Canvas-elements
<Window x:Class="WPFTryOut.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Canvas Name="rootCanvas" ZIndex="1">
<Canvas Name="Canvas2" Width="100" Height="100" ZIndex="0" Background="Aquamarine" Left="30" Top="30" MouseLeftButtonDown="DragStart" MouseMove="Drag" PreviewMouseLeftButtonUp="DragEnd">
<Rectangle Canvas.Left="10" Canvas.Top="10" Width="20" Height="20" Fill="Blue" MouseLeftButtonDown="DragStart" MouseMove="Drag" PreviewMouseLeftButtonUp="DragEnd"></Rectangle>
<Rectangle Canvas.Left="40" Canvas.Top="60" Width="20" Height="20" Fill="Red" MouseLeftButtonDown="DragStart" MouseMove="Drag" PreviewMouseLeftButtonUp="DragEnd"></Rectangle>
</Canvas>
<Canvas Name="Canvas3" Width="100" Height="100" ZIndex="0" Background="Aquamarine" Left="330" Top="30" MouseLeftButtonDown="DragStart" MouseMove="Drag" PreviewMouseLeftButtonUp="DragEnd">
</Canvas>
</Canvas>
</Grid>
</Window>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace WPFTryOut
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
bool _captured;
double _left, _top, _canvasX, _canvasY, _originalLeft, _originalTop;
UIElement _draggedElement;
private Canvas _draggedOverCanvas;
private Canvas _originalParentCanvas;
private void DragStart(object sender, MouseButtonEventArgs e)
{
_draggedElement = (UIElement)sender;
Mouse.Capture(_draggedElement);
_captured = true;
// Store original situation for possible reset
_originalParentCanvas = (Canvas)LogicalTreeHelper.GetParent(_draggedElement);
_originalLeft = Canvas.GetLeft(_draggedElement);
_originalTop = Canvas.GetTop(_draggedElement);
// store coordinates
_left = _originalLeft;
_top = _originalTop;
_canvasX = e.GetPosition(rootCanvas).X;
_canvasY = e.GetPosition(rootCanvas).Y;
// For objects in another canvas, check if it is not the root canvas, than change the parent to the root canvas and update coordinates.
// While in drag-mode, the element belongs to the root canvas.
if (_originalParentCanvas != null && _originalParentCanvas != rootCanvas && _originalParentCanvas.Children.Contains(_draggedElement))
{
_originalParentCanvas.Children.Remove(_draggedElement);
rootCanvas.Children.Add(_draggedElement);
_left += Canvas.GetLeft(_originalParentCanvas);
_top += Canvas.GetTop(_originalParentCanvas);
}
// Do not drag any other objects
e.Handled = true;
}
private void Drag(object sender, MouseEventArgs e)
{
if (_captured)
{
// Get new mouse position relative to root canvas
double x = e.GetPosition(rootCanvas).X;
double y = e.GetPosition(rootCanvas).Y;
// Change left and top of UIElement by the mouse-movement (new position - old position)
_left += x - _canvasX;
_top += y - _canvasY;
Canvas.SetLeft(_draggedElement, _left);
Canvas.SetTop(_draggedElement, _top);
// Store new mouse position
_canvasX = x;
_canvasY = y;
// Highlight (or UNhighlight) the canvas you are dragging over. Also: Store it (as a future target).
var hitTestResult = VisualTreeHelper.HitTest(rootCanvas, e.GetPosition(rootCanvas));
if (hitTestResult != null && hitTestResult.VisualHit != null)
{
var hit = hitTestResult.VisualHit as Canvas;
if (hit != null && hit != _draggedOverCanvas)
{
if (_draggedOverCanvas != null)
_draggedOverCanvas.Background = Brushes.Aquamarine;
_draggedOverCanvas = hit;
hit.Background = Brushes.Yellow;
}
}
else
{
if (_draggedOverCanvas != null)
_draggedOverCanvas.Background = Brushes.Aquamarine;
_draggedOverCanvas = null;
}
}
e.Handled = true;
}
private void DragEnd(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
_captured = false;
// if there is a target canvas
if (_draggedOverCanvas != null)
{
_draggedOverCanvas.Background = Brushes.Aquamarine;
// and you are not dragging a canvas itself
if (_draggedElement.GetType() != typeof(Canvas))
{
// add the element to the new canvas
rootCanvas.Children.Remove(_draggedElement);
_draggedOverCanvas.Children.Add(_draggedElement);
// and update its coordinates
var newLeft = _left - Canvas.GetLeft(_draggedOverCanvas);
var newTop = _top - Canvas.GetTop(_draggedOverCanvas);
Canvas.SetLeft(_draggedElement, newLeft);
Canvas.SetTop(_draggedElement, newTop);
}
_draggedOverCanvas = null;
}
// otherwise reset the element to its original position
else
{
if (_draggedElement.GetType() != typeof(Canvas))
{
// add the element to the original canvas
rootCanvas.Children.Remove(_draggedElement);
_originalParentCanvas.Children.Add(_draggedElement);
// and restore its coordinates
Canvas.SetLeft(_draggedElement, _originalLeft);
Canvas.SetTop(_draggedElement, _originalTop);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment