I've created a custom behaviour (without blend) for dragging UIElements and getting a translucent thumbnail of what you're dragging under the cursor (blends version moves the target object which isn't what I need)
Anyhoo, the code is actually very simple and works nicely, the problem I'm having is that onDetaching() isn't being called, which means my events to the UIElement aren't being unhooked.
This worries me a little as I'm guessing the only reason why the behaviour isn't being detached is because it's still being referenced by something. It shouldn't be the UIElement it's self though as we had leakage problems with it at one stage but we've now resolved them and this is clarified through WinDbg.
The only interesting(?) thing about it is the behaviour is attached to an image in an items control, but this shouldn't make a difference right?
Here's my current code:
public class DragBehavior : Behavior<UIElement>
{
private const double DRAG_DISTANCE = 20;
private const int DRAG_ICON_HEIGHT = 100;
Point m_firstPoint;
private bool m_isDragging = false;
private Popup m_dragPopup = null;
private Image m_draggedImage;
protected override void OnAttached()
{
this.AssociatedObject.MouseLeftButtonDown += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
this.AssociatedObject.MouseMove += new MouseEventHandler(AssociatedObject_MouseMove);
this.AssociatedObject.MouseLeftButtonUp += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
base.OnAttached();
}
void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
m_firstPoint = e.GetPosition(null);
m_isDragging = true;
}
void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
{
if (m_isDragging)
{
Point currentPosition = e.GetPosition(null);
if (m_dragPopup == null)
{
double deltaX = currentPosition.X - m_firstPoint.X;
double deltaY = currentPosition.Y - m_firstPoint.Y;
double movement = Math.Sqrt((deltaX * deltaX) + (deltaY * deltaY));
if (movement > DRAG_DISTANCE)
{
// Get a screen shot of the element this behaviour is attached to
WriteableBitmap elementScreenshot = new WriteableBitmap(AssociatedObject, null);
// Create an image out of it
m_draggedImage = new Image();
m_draggedImage.Height = DRAG_ICON_HEIGHT;
m_draggedImage.Stretch = Stretch.Uniform;
m_draggedImage.Source = elementScreenshot;
m_draggedImage.Opacity = 0.4;
// Add the image to the popup
m_dragPopup = new Popup();
m_dragPopup.Child = m_draggedImage;
m_dragPopup.IsOpen = true;
m_dragPopup.UpdateLayout();
m_dragPopup.HorizontalOffset = currentPosition.X - m_draggedImage.ActualWidth/2;
m_dragPopup.VerticalOffset = currentPosition.Y - m_draggedImage.ActualHeight/2;
AssociatedObject.CaptureMouse();
}
}
else
{
m_dragPopup.HorizontalOffset = currentPosition.X - m_draggedImage.ActualWidth/2;
m_dragPopup.VerticalOffset = currentPosition.Y - m_draggedImage.ActualHeight/2;
}
}
}
void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (m_isDragging == true && m_dragPopup != null)
{
m_isDragging = false;
m_dragPopup.IsOpen = false;
m_dragPopup = null;
}
AssociatedObject.ReleaseMouseCapture();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
protected override void OnDetaching()
{
this.AssociatedObject.MouseLeftButtonDown -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
this.AssociatedObject.MouseMove -= new MouseEventHandler(AssociatedObject_MouseMove);
this.AssociatedObject.MouseLeftButtonUp -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
base.OnDetaching();
}
}
I know of two posts which I've seen about this...
This one - forums.silverlight.net/forums/p/142038/317146.aspx doesn't help as I've tried forcing a GC to no avail, and this one - Automatically calling OnDetaching() for Silverlight Behaviors I don't really get their explination as they claim its the hooking up of the UIElement to the behaviour that causes it, but surely when the root reference UIElement is broken, the root reference to the behaviour will be removed too and consequently both become eligable for GC.
I was hoping this'd be simple, but if not I'll get started with WinDbg to see what's actually going on!
Any help is much appreciated! :)
Thanks,
Andy.