How to update the position of a drag adorner during WPF drag-n-drop?

IanR picture IanR · Jan 19, 2010 · Viewed 12.1k times · Source

I'm using an adorner to show a 'ghost' of the element being dragged...

var adornerLayer = AdornerLayer.GetAdornerLayer(topLevelGrid);
dragAdorner = new DragAdorner(topLevelGrid, itemToDrag);
adornerLayer.Add(dragAdorner);
dragAdorner.UpdatePosition(e.GetPosition(topLevelGrid));

DragDrop.DoDragDrop(sourceItems, viewModel, DragDropEffects.Move);

adornerLayer.Remove(dragAdorner);
itemToDrag = null;

...but I can't find a nice way to update the position of the adorner during the drag. The closest I've got is by setting AllowDrop="true" on the top level grid and giving it a DragOver handler...

private void TopLevelGrid_OnDragOver(object sender, DragEventArgs e)
{
 dragAdorner.UpdatePosition(e.GetPosition(topLevelGrid));
}

But this means I don't get the proper DragDropEffects feedback on the cursor, i.e., it always shows the DragDropEffects.Move cursor instead of DragDropEffects.None until I'm over an actual drop target.

Does anyone know a better way to update the adorner position?

Answer

Markus Hütter picture Markus Hütter · Jan 20, 2010

There's this (unfortunately only available as a cached version) pretty old blog post from Bea Stollnitz, which pretty much covers your question. It has a nice implementation of drag n drop with an adorner showing a "ghost image".

Basically drag and drop in WPF is quite the complicate procedure that - if you want some custom DragAdorners - involves adding a bunch of attached dependency properties for handling setup of all the events involved and especially for displaying the adorner in a way that doesn't interfere with the dropping code.

Bea's code works by having a helper class that sets the owning Window's DragOver event handler and AllowDrop right before the actual drag drop operation, that way you can control all the moving in between the actual drag source and the drop target.