WPF拖放 - DragLeave事件何时触发?

17

当从父控件拖动到子控件时,我会收到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

在此输入图像描述


可能是DragDrop - DragEnter/DragLeave Events keep firing的重复问题。 - G.Y
1个回答

21

最近我一直在开发一个使用WPF拖放功能的应用程序,在为同样的问题进行了半天的调试、查找和重读文档之后,我只能得出结论:WPF库中可能存在一个“未来改进”的问题。

拖放系统中似乎有一个小问题。当用户将对象拖动到我们的控件上方时,系统会经常发送DragLeave事件,紧接着是DragEnter事件。因此,当我们收到DragLeave事件时,我们不能确定拖放操作是否已经终止。因此,我们不会立即进行清理,而是安排稍后执行清理操作,如果在这段时间内我们收到另一个DragEnterDragOver事件,则不进行清理。

这是我的解决方案:

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 );
}

谢谢DXM,这似乎解决了绝大多数子控件的问题。然而,拖动分隔符控件(以及其他一些控件)会导致OnQueryDragDataValid方法被调用。 - PeterM
1
@Peter,我在那里添加的OnQueryDragDataValid()调用是为了我的特定实现。如果您不需要它,我认为它不需要存在。我的设计(我认为WPF也希望这样)是OnQueryDragDataValid()可以被任意次数调用,您只需要验证拖放操作是否有效即可。 - DXM
@DMX,是的,你说得完全正确。我本意是要写OnRealTargetDragLeave在拖动到分隔符控件上时触发。我相信这是因为“分隔符控件不对任何键盘、鼠标、鼠标滚轮或平板输入做出反应,也不能被启用或选择。(来自MSDN)”。然而,分隔符可以很容易地被其他类似的控件(线条、矩形等)替换,并且能够正常工作。再次感谢你提供的好方法! - PeterM
@DXM,我尝试了这个解决方案来处理按钮、标签和矩形,但是我的dragLeave事件仍然会触发。我该怎么办? - Ana
2
@DMX。谢谢您先生!我发现在执行OnDragOver之前会调用OnDragEnter方法。因此,在OnDragEnter中我也添加了_dragInProgress = true。效果非常好! - Steffen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接