WPF Drag Drop - когда DragLeave Fire?

Я получаю события DragLeave при перетаскивании из родительского элемента в дочерний элемент управления. Я бы только ожидал получить это событие, когда выходим за пределы контроля. Как это реализовать?

Обратитесь к этому простому образцу приложения.

<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>

и в коде

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

Ответы

Ответ 1

Недавно я работал над своим собственным приложением, которое широко использует перетаскивание WPF и, проведя полдня (отладка, поиск в Интернете, перечитывая документацию) по той же самой проблеме, которую вы видите, я мог только заключить там "будущее совершенствование" похоронено где-то в библиотеке WPF.

Это было мое решение:

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

        // It appears there a quirk in the drag/drop system.  While the user is dragging the object
        // over our control it appears the system will send us (quite frequently) DragLeave 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.
        _target.Dispatcher.BeginInvoke( new Action( ()=> {
                                if( _dragInProgress == false ) OnRealTargetDragLeave( sender, e ); } ) );
    }

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

        OnQueryDragDataValid( sender, e );
    }