全网首发:CefSharp 自定义右键菜单 (Winform版)
网上有关CefSharp For WPF自定义右键菜单栏的文章数不胜数,而如果你是使用Winform开发cefsharp浏览器,可能会对此一筹莫展.
例如如下帖子的楼主等,可能需要知道我这篇文章.
https://q.cnblogs.com/q/128013/
https://segmentfault.com/q/1010000023019239
为什么网上流传的只有WPF版本,而没有Winform版本的呢,去cefsharp的github逛了一圈,才知道原来多是转载官方的Example.
https://github.com/cefsharp/CefSharp/blob/cefsharp/75/CefSharp.Wpf.Example/Handlers/MenuHandler.cs
而很不幸的是,官方没有给出Winform版本的Example ,这个时候就需要自己从wpf代码中翻译了.
右键菜单功能由IContextMenuHandler接口定义.
具体代码如下:
/* 引用
using CefSharp;
using CefSharp.WinForms;
using System;
using System.Collections.Generic;
*/
public class MenuHandler : IContextMenuHandler
{
void IContextMenuHandler.OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model)
{
//主要修改代码在此处;如果需要完完全全重新添加菜单项,首先执行model.Clear()清空菜单列表即可.
//需要自定义菜单项的,可以在这里添加按钮;
if (model.Count > 0)
{
model.AddSeparator();//添加分隔符;
}
model.AddItem((CefMenuCommand)26501, "Show DevTools");
model.AddItem((CefMenuCommand)26502, "Close DevTools");
}
bool IContextMenuHandler.OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags)
{
//命令的执行,点击菜单做什么事写在这里.
if (commandId == (CefMenuCommand)26501)
{
browser.GetHost().ShowDevTools();
return true;
}
if (commandId == (CefMenuCommand)26502)
{
browser.GetHost().CloseDevTools();
return true;
}
return false;
}
void IContextMenuHandler.OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
var webBrowser = (ChromiumWebBrowser)browserControl;
Action setContextAction = delegate ()
{
webBrowser.ContextMenu = null;
};
webBrowser.Invoke(setContextAction);
}
bool IContextMenuHandler.RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback)
{
//return false 才可以弹出;
return false;
}
//下面这个官网Example的Fun,读取已有菜单项列表时候,实现的IEnumerable,如果不需要,完全可以注释掉;不属于IContextMenuHandler接口规定的
private static IEnumerable<Tuple<string, CefMenuCommand, bool>> GetMenuItems(IMenuModel model)
{
for (var i = 0; i < model.Count; i++)
{
var header = model.GetLabelAt(i);
var commandId = model.GetCommandIdAt(i);
var isEnabled = model.IsEnabledAt(i);
yield return new Tuple<string, CefMenuCommand, bool>(header, commandId, isEnabled);
}
}
}
调用很简单,如下:
//在初始化ChromiumWebBrowser后,指定其MenuHandler 即可.
browser1.MenuHandler = new MenuHandler();
这样就实现了自定义菜单项,及设定自定义菜单项的功能.
关于代码,再啰嗦几点:
1.CefSharp右键菜单功能由IContextMenuHandler接口定义.
2.有的人看了官方的例子,可能会卡在webBrowser.Dispatcher.Invoke上面. winfrom中是没有Dispatcher的,Dispatcher只是调度器,在winform中直接使用Invoke调用即可,跟平时写的跨线程的UI访问需要使用委托来访问以确保线程安全一样.
3.官方的Example也是显示实现接口,文章代码尽量与翻译官方Example所以写的显示实现接口,实际上隐式实现接口是一样可用的.
4.官方Example中在 RunContextMenu 方法中写了一大串的代码,实现了完整的WPF菜单栏绘制,是对winform版本的开发者的主要误导之一。(实际上Example中有注释申明了使用内置的ContextMenu只需要返回false即可,是由于WPF中需要集成到现有的消息循环中才需要重绘)
所以遇到问题还是要多看官方的文档,因为转载者基本上把这段注释改掉了,如果你尝试在winform中在这里模仿wpf代码进行重绘,测了下可以成功,但是弹出速度极慢,重绘代码不发了,因为弹出速度感人毫无参考意义,winform即便是要重绘也应该是在OnBeforeContextMenu里面设定才对.
关于需要彻底禁用右键菜单,只要理解了上面的代码,就应该知道有很多很多处地方都可以实现,随便任意一处即可.
5. 右键菜单中的点击后的功能是什么,这些都是可以自己设定的.
右键菜单的功能的设定和可以实现的功能,不一定局限于浏览器基础功能的范畴,
也可以实现其它浏览器之外的其它任务和工作也是可以的,灵活运用即可.