Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Drag Drop - When Does DragLeave Fire?

Tags:

.net

vb.net

wpf

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

like image 382
PeterM Avatar asked Mar 27 '11 04:03

PeterM


1 Answers

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 );
}
like image 99
DXM Avatar answered Nov 09 '22 17:11

DXM