WPF-在拖放过程中跟踪鼠标当AllowDrop = False时下降 [英] WPF - Track mouse during Drag & Drop while AllowDrop = False

查看:106
本文介绍了WPF-在拖放过程中跟踪鼠标当AllowDrop = False时下降的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个Adorner,在拖动&期间会跟随鼠标放下操作。即使鼠标悬停在AllowDrop设置为False的元素上,它也需要这样做。

I'm trying to create an Adorner that will follow the mouse during a drag & drop operation. It needs to do so even when the mouse is dragging over an element that has AllowDrop set to False.

问题:


  • 在拖放过程中不会触发普通鼠标事件(例如MouseMove)。删除

  • 拖放放置事件(例如DragOver,GiveFeedback)仅在有效的放置目标(AllowDrop设置为true的元素)上触发

我需要跟踪:


  • 鼠标在哪里

  • 鼠标移动时

没有上述任何事件,我很难找到做到这一点的方法。

Without any of the above events, there's no easy way I can find to do this.

我已经通过使用本机GetCursorPos方法解决了#1问题。只要我愿意,就可以可靠地获得鼠标的位置。

I've solved #1 by using the native GetCursorPos method. This can reliably get the position of the mouse whenever I want.

我剩下的问题是在鼠标移动时得到通知。有什么方法可以在拖放过程中获得鼠标移动通知吗?

My remaining problem is getting notified when the mouse moves. Is there any way I can get mouse movement notifications during a drag & drop operation, even when dragging over elements with AllowDrop set to false?

注意:我不想使用计时器而只是连续刷新位置(如果可以的话,是否可以放下操作)?

Note: I don't want to use a timer and just continuously refresh the position (if I can help it), I'd much rather use actual mouse input.

推荐答案

哇,我没想到这个会

我的第一个尝试是尝试绕过WPF并直接转到本机窗口消息泵。但是事实证明,即使在拖放操作期间,标准WM_MOUSEMOVE消息也不会通过。深入研究(通过ole2.dll源代码),我发现在拖动过程中创建了一个单独的不可见窗口,该窗口吞噬了所有正常消息,而是直接与放置目标接口(这可能是正常WPF鼠标事件的原因)

My first attempt was to try and bypass WPF and go straight to the native window message pump. But it turns out that even the standard WM_MOUSEMOVE message doesn't come through during a drag and drop operation. Digging deeper (through the ole2.dll source code), I discovered that a separate, invisible window gets created during the drag which eats up all the normal messages and instead interfaces with the drop targets directly (which is probably why the normal WPF mouse events don't fire in the first place).

我担心这可能会结束,直到我发现钩子,使您可以在活动窗口使用它们之前获取大量消息。使用WH_MOUSE钩子,我可以截获WM_MOUSEMOVE消息并相应地放置我的Adorner。

I was worried that might be the end of it, until I discovered hooks, which let you get a hold of messages before they're consumed by the active window. Using the WH_MOUSE hook I was able to intercept the WM_MOUSEMOVE message and place my Adorner accordingly.

我不会在此处发布有关Adorner的所有代码,但是我将为您提供我用来跟踪鼠标的P /调用代码:

I'm not going to post all the code for the Adorner here, but I will give you the P/Invoke code I used to track the mouse:

Module NativeMethods
    <DllImport("user32.dll")>
    Public Function SetWindowsHookEx(ByVal idHook As HookType, ByVal lpfn As [Delegate], ByVal hInstance As IntPtr, ByVal threadId As Integer) As IntPtr
    End Function

    <DllImport("user32.dll")>
    Public Function CallNextHookEx(ByVal hhk As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    End Function

    <DllImport("user32.dll")>
    Public Function UnhookWindowsHookEx(ByVal hhk As IntPtr) As Boolean
    End Function

    <StructLayout(LayoutKind.Sequential)>
    Friend Structure Win32Point
        Public X As Int32
        Public Y As Int32

        Public Shared Widening Operator CType(Point As Win32Point) As Drawing.Point
            Return New Drawing.Point(Point.X, Point.Y)
        End Operator

        Public Shared Widening Operator CType(Point As Win32Point) As Windows.Point
            Return New Windows.Point(Point.X, Point.Y)
        End Operator
    End Structure

    Const WM_MOUSEMOVE As Integer = 512

    Enum HookType As Integer
        WH_JOURNALRECORD = 0
        WH_JOURNALPLAYBACK = 1
        WH_KEYBOARD = 2
        WH_GETMESSAGE = 3
        WH_CALLWNDPROC = 4
        WH_CBT = 5
        WH_SYSMSGFILTER = 6
        WH_MOUSE = 7
        WH_HARDWARE = 8
        WH_DEBUG = 9
        WH_SHELL = 10
        WH_FOREGROUNDIDLE = 11
        WH_CALLWNDPROCRET = 12
        WH_KEYBOARD_LL = 13
        WH_MOUSE_LL = 14
    End Enum

    Public Delegate Function HookProc(ByVal code As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer

    <StructLayout(LayoutKind.Sequential)>
    Structure MOUSEHOOKSTRUCT
        Public pt As Win32Point
        Public hwnd As IntPtr
        Public wHitTestCode As UInteger
        Public dwExtraInfo As IntPtr
    End Structure
End Module

Class MouseTracker
    Private HookHandle As IntPtr
    Private HookDelegate As New HookProc(AddressOf NativeHook)

    Private Sub AddNativeHook()
#Disable Warning BC40000 ' Type or member is obsolete
        HookHandle = SetWindowsHookEx(HookType.WH_MOUSE, HookDelegate, IntPtr.Zero, AppDomain.GetCurrentThreadId())
#Enable Warning BC40000 ' Type or member is obsolete
    End Sub

    Private Sub RemoveNativeHook()
        UnhookWindowsHookEx(HookHandle)
    End Sub

    Private Function NativeHook(code As Integer, wParam As IntPtr, lParam As IntPtr) As Integer
        If code >= 0 Then
            If wParam = WM_MOUSEMOVE Then
                Dim data = Marshal.PtrToStructure(Of MOUSEHOOKSTRUCT)(lParam)
                'From here you can use Visual.PointFromScreen(data.pt) to get the coordinates of the mouse relative to any WPF Visual.
                'Then you do whatever you want with that!
            End If
        End If

        Return CallNextHookEx(IntPtr.Zero, code, wParam, lParam)
    End Function
End Class

如果您需要更多信息,我会大量引用:

pinvoke.net: https://pinvoke.net/default.aspx/user32/SetWindowsHookEx.html

钩子上的Microsoft文档: https:// docs。 microsoft.com/en-us/windows/win32/winmsg/about-hooks

If you need more information, I heavily referenced:
pinvoke.net: https://pinvoke.net/default.aspx/user32/SetWindowsHookEx.html
Microsoft docs on hooks: https://docs.microsoft.com/en-us/windows/win32/winmsg/about-hooks

这篇关于WPF-在拖放过程中跟踪鼠标当AllowDrop = False时下降的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆