17

I am getting DragLeave Events when dragging from a parent to child control. I would only expect to get this event when moving outside the bounds of a control. How can I implement this?

Please refer to this simple sample application.

<Window x:Class="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">
    <StackPanel>
        <TextBox Height="50" >Hilight and Drag this text</TextBox>
        <Border BorderBrush="Blue" BorderThickness="2">
            <StackPanel AllowDrop="True" Name="Stack" >
                <Label >If I drag text across the gray line, Stack.DragLeave will fire.</Label>
                <Separator></Separator>
                <Label>I only expect to get this event when leaving the blue rectangle. </Label>
            </StackPanel>
        </Border>
        <TextBlock >Stack.DragLeave Count: <Label x:Name="countLabel" /></TextBlock>
    </StackPanel>
</Window>

and in the code behind

Class MainWindow

    Private Sub Stack_DragLeave(ByVal sender As Object, ByVal e As System.Windows.DragEventArgs) Handles Stack.PreviewDragLeave
        countLabel.Content = countLabel.Content + 1
    End Sub

End Class

enter image description here

PeterM
  • 2,372
  • 1
  • 26
  • 35
  • possible duplicate of [DragDrop - DragEnter/DragLeave Events keep firing](http://stackoverflow.com/questions/2632821/dragdrop-dragenter-dragleave-events-keep-firing) – G.Y Aug 11 '15 at 19:29

1 Answers1

21

I've recently been working on my own application that is using WPF drag/drop extensively and after spending half a day (debugging, googling, re-reading documentation) on exactly same issue you are seeing, I could only conclude there's a "future enhancement" buried somewhere in WPF library.

It appears there's a quirk in the drag/drop system. While the user is dragging the object over our control it appears the system will quite frequently send us DragLeave events, followed immediately by DragEnter events. So when we get DragLeave, we can't be sure that the drag/drop operation was actually terminated. Therefore, instead of doing cleanup immediately, we schedule the cleanup to execute later and if during that time we receive another DragEnter or DragOver event, then we don't do the cleanup.

This was my solution:

protected virtual void OnTargetDragLeave(object sender, DragEventArgs e)
{
    _dragInProgress = false;

    _target.Dispatcher.BeginInvoke( new Action( ()=> 
    {
        if( _dragInProgress == false ) OnRealTargetDragLeave( sender, e ); 
    } ) );
}

protected virtual void OnTargetDragOver(object sender, DragEventArgs e)
{
    _dragInProgress = true;

    OnQueryDragDataValid( sender, e );
}
Sheridan
  • 68,826
  • 24
  • 143
  • 183
DXM
  • 4,413
  • 1
  • 19
  • 29
  • Thanks DXM, this seems to fix the problem for a vast majority of children controls. However, dragging over the seperator control (and perhaps others as well) cause the OnQueryDragDataValid method to be invoked. – PeterM Mar 27 '11 at 13:53
  • 1
    @Peter, the call to OnQueryDragDataValid() that I added in there was for my specific implementation. I don't think it needs to be there, if you don't need it. My design (and I think WPF also wants it that way) was that OnQueryDragDataValid() can be called any number of times and you simply need to verify that drop operation would be valid. – DXM Mar 28 '11 at 06:35
  • @DMX, Yes you are absolutly right. I meant to write that OnRealTargetDragLeave fires when dragging over a separator control. I believe this is because "Separator controls do not react to any keyboard, mouse, mouse wheel, or tablet input and cannot be enabled or selected. (From MSDN)". However, separators can easily be replaced with other similar controls (line, rectangle, etc) that will work. Thanks again for the great work-around! – PeterM Mar 29 '11 at 02:53
  • @DXM I tried this solution for button, label nd rectangle as well, but still my dragLeave event fires. What should I do? – Ana Nov 30 '15 at 11:41
  • 2
    @DMX. Thank you Sir! I find the OnDragEnter Method to be called before the OnDragOver. So I also added `_dragInProgress = true` in the OnDragEnter. Works like a charm! – Steffen Feb 17 '16 at 14:41