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

问题描述 投票:1回答:1

我正在使用windowsformshost并尝试获取dragover和drop事件。

我在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(窗口)?

winforms cefsharp chromium-embedded
1个回答
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

一旦你有了这个句柄并且你已经将它作为drop target撤销,那么你可以调用RegisterDragDrop传递句柄和你的IOleDropTarget类。

我的一些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中为WinForms看一些好东西,特别是因为控件有一大堆或无用的属性(AllowDrop)和事件(拖放)此时尚未实现。

© www.soinside.com 2019 - 2024. All rights reserved.