none
关于DragEnter/Leave的一个蛋疼问题 RRS feed

  • 常规讨论

  • 描述:GRID里面有若干个FrameworkElement(某些可能会越过GRID的边界),现在要求GRID响应DragEnter/Leave事件。就是拖入GRID以及其子元素的范围时执行A,拖出GRID的范围时执行B。
    现在问题是在GRID的范围内拖动,GRID内的子元素也会发生DragEnter/Leave事件,导致DragEnter/Leave执行多次,而我却不希望得到这种“好处”。
    如果使用EventTrigger的话,就不存在这个问题了,但EventTrigger只能添加StoryBoard而无法添加处理程序。

    请问各位有处理DragEnter和DragLeave的经验吗?对于上述问题有没有好点的解决方案?

    ps:EventTrigger对DragEnter和DragLeave做了特殊处理?

     

     

    ...........这问题让楼主蛋疼好多天了...

    • 已更改类型 Coolever 2010年11月15日 0:20
    2010年11月15日 0:17

全部回复

  • 你好,

    你可以处理PreviewDragEnter/Leave在Grid上,然后设置e.Handled=true; 这样就可以终止隧道路由事件往Grid的子元素上去。

    关于路由事件,楼主可以花点时间看下下面的文档 http://msdn.microsoft.com/zh-cn/library/ms742806.aspx

    致,

    Bob Bao


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Are you looking for a typical code sample? Please download all in one code framework !
    2010年11月15日 9:31
    版主
  • 现在用的正是隧道路由事件,从拖进Grid然后在Grid范围内拖来拖去经过若干个子元素时,会发生

    PreviewDragEnter(OriginalSource=Grid,sender=Grid)

    PreviewDragLeave(OriginalSource=Grid,sender=Grid)

    PreviewDragEnter(OriginalSource=SonElement,sender=Grid)

    PreviewDragLeave(OriginalSource=SonElement,sender=Grid)

     

    PreviewDragEnter(OriginalSource=Grid,sender=Grid)

    PreviewDragLeave(OriginalSource=Grid,sender=Grid)

    PreviewDragEnter(OriginalSource=SonElement,sender=Grid)

    PreviewDragLeave(OriginalSource=SonElement,sender=Grid)

    ................

    依据鼠标是否还在Grid或者其子元素范围内(某些子元素的Margin可能是(-100,-100,0,0))来设置e.Handle

    但在PreviewDragLeave的时候e.GetPosition(Grid)返回相对Grid的坐标怎么看都不正确。

    只能用ScreenPosition获取FrameworkElement的屏幕坐标和Win32方法来获取鼠标的屏幕坐标,加上ActualHeight和ActualWidth来对比。但这方法有个问题,当其他窗口挡住Grid的一部分时,这样做会变得不可靠。

    不知道有没有好一点的方法来处理呢,EventTrigger的DragEnter就做得很完美了,可惜它只支持Storyboard。。。我尝试过继承EventTrigger。。水平太低失败了- -!

     

    2010年11月15日 21:39
  • 你好,

    你可以尝试用HitTest来进行点击测试,这样会返回指定坐标上的可见元素,详见:http://msdn.microsoft.com/en-us/library/system.windows.uielement.inputhittest.aspx

    如果你在点击测试时返回了一个Grid内元素,那么这个点就在Grid内。还有 你也可以通过VisualTreeHelper.GetDescendantBounds来获得Grid的范围,然后再Rect.Contain判断这个点的位置。

    还有,建议你能够实现PreviewDragOver事件来进行点位置的判断。

    致,

    Bob Bao


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Are you looking for a typical code sample? Please download all in one code framework !
    2010年11月16日 2:09
    版主
  • 你好,Bob Bao

    HitTest只能在PreviewDragEnter和PreviewDragOVer里面用,前文说过了,PreviewDragLeave和DeagLeave里面e.GetPosition获取不到正确的坐标。。。用User32.dll的GetCousePos感觉不太雅观。。

    我在寻找有没有更原生的方法来实现复杂ElementTree作为DragTarget的拖动操作。。。

    2010年11月16日 8:23
  • 你好,

    回到你的原始问题,你不希望拖拽移出Grid,但是由于冒泡路有事件 在Grid的子元素上发生并且触发了Grid的相关事件,导致了对象无法判定是否移出Grid.这个问题, 你可以通过判断事件参数 e.OriginalSource 来避免。 如果触发事件原始源不是Grid 那么就是他的子元素。

    然后,关于坐标问题,网上我找到了相关他的转换,代码是比较标准的,应该不会影响到你的代码美观度 :). 请参看下列连接和他们提供的样例:http://www.codeproject.com/KB/WPF/ListViewDragDropManager.aspx

    里面有一个类,MouseUtilities 可以实现坐标转换的,希望对你有用。

    致,

    Bob Bao


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Are you looking for a typical code sample? Please download all in one code framework !
    2010年11月16日 11:30
    版主
  • “对象无法判定是否移出Grid”。。。单凭e.OriginalSource应该是判断不了的,特别是SonElement跨过了Grid的边界的时候。

    ps:我在某WPF群上有见过好像你名字的,不知道是不是你~:)

    2010年11月16日 17:44
  • Bob Bao 你好

    连接的内容原来我之前早下过了,是用ScreenPosition和Win32 的GetCursorPos结合(前文有提到)。对于拖动的需求WPF应该有优雅的解决方案吧。。因为我对e.Data获取到的对象要处理一段时间。。。

    2010年11月16日 17:57