我正在开发一个使用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: 阅读完评论后,我决定更准确地描述代码流程:
preventDefault
事件的MouseEvent参数上设置ContextMenu
来阻止默认上下文菜单。windowForm.Invoke(Sub() ... )
,因为Main / Gui线程未收到消息,但必须在此处处理,才能正确显示上下文菜单。ContextMenuStrip
属性,该属性包含实际的ChromiumWebBrowser控件。ContextMenuStrip.Show(location)
方法显示。的问题:
答案 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
),它将监听器添加到相应的事件中。这以全球和简单的方式处理问题。
编辑: 上面提出的解决方案留下了这样的问题:点击禁用的浏览器控件按预期关闭了菜单,但丢失了,即浏览器无法处理它。我目前的解决方法是:
实施实际的解决方案在细节上引起了一些令人头疼的问题,但也许这对任何人都有帮助......