在ChromiumWebBrowser上显示Winforms Contextmenu

时间:2016-02-02 19:45:29

标签: winforms cefsharp

我正在开发一个使用CefSharp作为Gui的Winforms项目。出于几个原因,我想使用Winforms ContextMenu类实现自定义上下文菜单;在Html中呈现菜单或自定义ChromiumWebBrowser的上下文菜单(使用CefSharp.IContextMenuHandler)不是一个选项。

由Javascript代码触发的上下文菜单,它调用我传递给RegisterAsyncJsObject的.net对象上的方法;使用Javascript阻止默认上下文菜单。我正在调用Gui线程上的方法调用,因为通过“javascript bridge”调用注册对象来自不同的线程。

我的问题:当在CefSharp.WinForms.ChromiumWebBrowser上手动显示Winforms上下文菜单时,上下文菜单无法获得键盘焦点(例如,选择带箭头键的项目不起作用,也无法使用Esc关闭上下文菜单) ;相反,键盘焦点保留在ChromiumWebBrowser控件上。而且,如果我点击ChromiumWebBrowser的控制区域,则上下文菜单也不会关闭。我只能通过用鼠标选择一个项目或者单击表单中的另一个控件(包含ChromiumWebBrowser)或其他地方(例如桌面或其他应用程序)来关闭上下文菜单。

如果我从代码中的其他位置触发上下文菜单 - 最终使用调用myContextMenu.Show()的相同方法 - 上下文菜单会根据需要获取键盘焦点。但仍然存在一个问题:当我在ChromiumWebBrowser控件中单击时,它不会关闭。

我没有使用IFocusHander,IContextMenuHandler,IKeyboardHandler - 我应该吗?

我正在使用CEF 3.2454.1344.g2782fb8,Chromium 45.0.2454.101和.net 4.5.1。

不幸的是,提取演示代码是不可能的。

任何想法?

EDIT1: 阅读完评论后,我决定更准确地描述代码流程:

  • 右键单击时,Javascript会向已注册的.net对象发送一条消息,其中包含鼠标坐标。通过在preventDefault事件的MouseEvent参数上设置ContextMenu来阻止默认上下文菜单。
  • 已注册的.net对象接收消息并调用windowForm.Invoke(Sub() ... ),因为Main / Gui线程未收到消息,但必须在此处处理,才能正确显示上下文菜单。
  • 创建contextmenu并将其分配给UserControl的ContextMenuStrip属性,该属性包含实际的ChromiumWebBrowser控件。
  • 使用ContextMenuStrip.Show(location)方法显示。

的问题:

  • 上下文菜单没有键盘焦点。
  • 所有鼠标事件似乎被ChromiumWebBrowser“吞噬”:点击那里没有关闭上下文菜单。
  • 除了使用不同的“触发器”外,打开相同的上下文菜单工作正常,但第二期除外。

1 个答案:

答案 0 :(得分:0)

最后解决方案很简单;如果添加了以下步骤,一切都按实施和期望的方式工作:

在显示上下文菜单之前,使用ChromiumWebBrowser禁用UserControl并将焦点设置为拥有的表单;像这样的东西:

Private Sub showContextMenu(position As Point)
    Me.ctrlCefBrowser.Enabled = False
    Me.Focus()

    myContextMenu.Show(position)
End Sub

这使得焦点远离ChromiumWebBrowser,使上下文菜单有机会响应键盘输入。而且,通过禁用控件,鼠标事件不会被吞下"再点击浏览器区域会导致上下文菜单再次消失。

然后,最后,在上下文菜单中添加一个事件处理程序,以便再次重新启用浏览器控件:

Private Sub myContextMenu_Closed(sender As Object, e As ToolStripDropDownClosedEventArgs) Handles myContextMenu.Closed
    Me.ctrlCefBrowser.Enabled = True
    Me.ctrlCefBrowser.Focus()
End Sub

这对我有用,现在我的webbrowser控件有一个完全可自定义的Gdi上下文菜单:o)

注意: 当使用其他菜单时也会出现类似的问题,例如,在主菜单或工具栏中:单击ChromiumWebBrowser控件不会关闭菜单(因为鼠标事件也是"吞下")。可以应用相同的解决方案:打开下拉菜单时,停用(Enabled = False)Web浏览器控件。当它关闭时,重新激活它。对于我的菜单,我使用了一个派生类(Inherits ToolStripMenuItem),它将监听器添加到相应的事件中。这以全球和简单的方式处理问题。

编辑: 上面提出的解决方案留下了这样的问题:点击禁用的浏览器控件按预期关闭了菜单,但丢失了,即浏览器无法处理它。我目前的解决方法是:

  • 不要禁用浏览器控件。
  • 使用菜单项和上下文菜单的开始事件,跟踪当前打开的菜单。
  • 当浏览器收到焦点时(可通过拦截WndProc消息获得)关闭打开的菜单。

实施实际的解决方案在细节上引起了一些令人头疼的问题,但也许这对任何人都有帮助......