如何使用CefSharp Winform接收拖动移动和拖放事件

时间:2019-02-15 14:37:52

标签: winforms cefsharp chromium-embedded

我正在使用Windowsformshost并尝试获取拖动和放置事件。

我在WPF窗口,Windowsformshost和ChromiumWebBrowser上设置了allowdrop。我可以理解,由于windowsformshost的空域问题,WPF窗口将无法获取事件。但是我不明白为什么Windowsformshost或ChromiumWebBrowser没有得到任何事件。看来它们被CEF / CefSharp吞没了并且没有被传递。如何处理事件和/或需要在CEF / CefSharp中禁用什么?

当我从纯WPF CefSharp迁移时,我已经使用WPF ChromiumWebBrowser(不使用IDragHandler)实现了Dragenter,Dragmove和Dragdrop。

我想要实现的是根据鼠标拖动的位置来显示不同的拖动效果,其次,我希望能够拦截放置事件,以首先检查用户在文件上载时放置的文件类型类型元素。

effect of disabling或调用RevokeDragDrop是什么,以及从Cefsharp的角度来看应调用哪个Hwnd(窗口)?

1 个答案:

答案 0 :(得分:0)

回答我自己的问题:可以恢复已被上游吞噬的拖放事件。

首先,我使用了如下所示的IOleDropTarget接口;

 <ComImport, Guid("00000122-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Interface IOleDropTarget
    <PreserveSig>
    Function OleDragEnter(
    <[In], MarshalAs(UnmanagedType.[Interface])> ByVal pDataObj As Object,
    <[In], MarshalAs(UnmanagedType.U4)> ByVal grfKeyState As Integer,
    <[In], MarshalAs(UnmanagedType.U8)> ByVal pt As Long,
    <[In], Out> ByRef pdwEffect As Integer) As Integer
    <PreserveSig>
    Function OleDragOver(
    <[In], MarshalAs(UnmanagedType.U4)> ByVal grfKeyState As Integer,
    <[In], MarshalAs(UnmanagedType.U8)> ByVal pt As Long,
    <[In], Out> ByRef pdwEffect As Integer) As Integer
    <PreserveSig>
    Function OleDragLeave() As Integer
    <PreserveSig>
    Function OleDrop(
    <[In], MarshalAs(UnmanagedType.[Interface])> ByVal pDataObj As Object,
    <[In], MarshalAs(UnmanagedType.U4)> ByVal grfKeyState As Integer,
    <[In], MarshalAs(UnmanagedType.U8)> ByVal pt As Long,
    <[In], Out> ByRef pdwEffect As Integer) As Integer
End Interface

接下来,当我们在界面上时,请使用该界面创建一个漂亮的图标,当用此界面拖动文件时,Windows资源管理器将显示该图标。

Imports IDataObject_Com = System.Runtime.InteropServices.ComTypes.IDataObject
Imports System.Windows.Interop
Imports System.Runtime.InteropServices

Namespace Browser
<StructLayout(LayoutKind.Sequential)>
Public Structure Win32Point
    Public x As Integer
    Public y As Integer
End Structure

<ComImport>
<Guid("4657278A-411B-11d2-839A-00C04FD918D0")>
Public Class DragDropHelper
End Class

<ComVisible(True)>
<ComImport>
<Guid("4657278B-411B-11D2-839A-00C04FD918D0")>
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Interface IDropTargetHelper
    Sub DragEnter(
 <[In]> ByVal hwndTarget As IntPtr,
 <[In], MarshalAs(UnmanagedType.[Interface])> ByVal dataObject As IDataObject_Com,
 <[In]> ByRef pt As Win32Point,
 <[In]> ByVal effect As Integer)
    Sub DragLeave()
    Sub DragOver(
 <[In]> ByRef pt As Win32Point,
 <[In]> ByVal effect As Integer)
    Sub Drop(
 <[In], MarshalAs(UnmanagedType.[Interface])> ByVal dataObject As IDataObject_Com,
 <[In]> ByRef pt As Win32Point,
 <[In]> ByVal effect As Integer)
    Sub Show(
 <[In]> ByVal show As Boolean)
End Interface

您需要实现IOleDropTaget接口,该接口随后将提供DragEnter,Over,Leave和Drop的事件。

要挂接这些事件,您不需要像上面提示的那样了解任何有关messageloop或wndproc消息的信息。您需要知道的是,其中一个类名为“ Chrome_WidgetWin_0”的Chromium窗口已注册用于拖放,必须首先将其吊销,然后才能获取事件。

CefSharp示例显示了如何深入Chromium窗口,但这通常是获得另一个窗口类的方法。在这种情况下,我将使用以下内容(请注意,我将撤消在回叫功能中找到的所有窗口,但似乎仅注册了Chrome_WidgetWin_0。

Const Chrome_WidgetWin As String = "Chrome_WidgetWin_0"

    Private Function TryFindHandl(ByVal browserHandle As IntPtr, <Out> ByRef chromeWidgetHostHandle As IntPtr) As Boolean

        Dim cbXL As New NativeMethodsEx.EnumChildCallback(AddressOf EnumChildProc_Browser)
        NativeMethodsEx.EnumChildWindows(browserHandle, cbXL, chromeWidgetHostHandle)

        Return chromeWidgetHostHandle <> IntPtr.Zero

    End Function

    Private Shared Function EnumChildProc_Browser(ByVal hwndChild As Integer, ByRef lParam As Integer) As Boolean
        Dim buf As New StringBuilder(128)
        NativeMethodsEx.GetClassName(hwndChild, buf, 128)
        Dim ret = NativeMethodsEx.RevokeDragDrop(hwndChild)

        If ret = NativeMethodsEx.DRAGDROP_E_NOTREGISTERED Then
            Debug.Print("")
        End If

        If buf.ToString = Chrome_WidgetWin Then
            lParam = hwndChild
            Return False
        End If
        Return True
    End Function

一旦有了此句柄并已将其撤销为放置目标,则可以通过传递句柄和IOleDropTarget类来调用RegisterDragDrop。

我的一些WinAPI签名如下

 Friend Const DRAGDROP_E_NOTREGISTERED = &H80040100
Friend Const DRAGDROP_E_INVALIDHWND = &H80040102
Friend Const DRAGDROP_E_ALREADYREGISTERED = &H80040101
Friend Const E_OUTOFMEMORY = &H8007000E
Friend Const S_OK = 0


<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Friend Shared Function GetClassName(ByVal hWnd As System.IntPtr, ByVal lpClassname As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer
End Function

Friend Delegate Function EnumChildCallback(ByVal hwnd As Integer, ByRef lParam As Integer) As Boolean

<DllImport("User32.dll")>
Friend Shared Function EnumChildWindows(ByVal hWndParent As Integer, ByVal lpEnumFunc As EnumChildCallback, ByRef lParam As Integer) As Boolean
End Function


<DllImport("ole32.dll")>
Friend Shared Function RegisterDragDrop(ByVal hwnd As IntPtr, DropTarget As Browser.IOleDropTarget) As IntPtr
End Function

<DllImport("ole32.dll")>
Friend Shared Function RevokeDragDrop(ByVal hwnd As IntPtr) As IntPtr
End Function

事件的示例以及如何使用IDropTargetHelper就像这样

Public Function OleDragEnter(<[In]> <MarshalAs(UnmanagedType.Interface)> pDataObj As Object, <[In]> <MarshalAs(UnmanagedType.U4)> grfKeyState As Integer, <[In]> <MarshalAs(UnmanagedType.U8)> pt As Long, <[In]> <Out> ByRef pdwEffect As Integer) As Integer Implements IOleDropTarget.OleDragEnter
        Dim winPT As Win32Point
        winPT.x = CInt(pt And &H7FFFFFFF)
        winPT.y = CInt((pt >> 32) And &H7FFFFFFF)
        Dim eff As DragDropEffects = DragDropEffects.None
        'this is my event I am sending back to the browser class to deal with.
        RaiseEvent DBDragEnter(eff, New Point(winPT.x, winPT.y))
        'you need to pass in the effect
        pdwEffect = CInt(eff)
        'this is the helper which shows the nice icon you drag around.
        ddHelper.DragEnter(targetHwnd, CType(pDataObj, IDataObject_Com), winPT, CInt(eff))
        Return NativeMethodsEx.S_OK
    End Function

当然可以在CefSharp for WinForms中看到一些东西,特别是因为该控件具有一堆或无用的属性(AllowDrop)和事件(拖放)目前尚未实现。