- A+
在WinForm/WPF中使用CefSharp混合开发时,通常需要自定义滚动条样式,以保证应用的整体风格统一。本文将给出一个简单的示例介绍如何自定义CefSharp中滚动条的样式。
基本思路
在前端开发中,通过CSS来控制滚动条的样式是件寻常的事情。CefSharp也提供了功能强大的API方便开发人员使用c#与JS进行交互。这也给我们提供了一个思路:在CefSharp加载完成后,使用其提供的ExecuteJavaScriptAsync
方法注入JS和CSS代码来自定义滚动条样式。
实现细节
为了排除干扰以及方便介绍,本文直接从GitHub上下载CefSharp.MinimalExample的示例代码进行修改。
首先用CSS定义滚动条的样式,介绍滚动条组成部分以及通过CSS控制其样式的文章挺多,比如MDN Web Docs。这里直接贴代码。
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/ ::-webkit-scrollbar { width: 6px; height: 6px; background-color: #FFF; cursor:pointer; } /*定义滚动条轨道 内阴影+圆角 */ ::-webkit-scrollbar-track { box-shadow: inset 0 0 6px rgba(155,155,155,0.3); border-radius: 5px; background-color: #FFF; cursor:pointer; } ::-webkit-scrollbar-button { display: none; } /*定义滑块 内阴影+圆角*/ ::-webkit-scrollbar-thumb { border:1px solid #c6c6c6; border-radius: 5px; background: #c6c6c6; cursor:pointer; background-repeat: no-repeat; background-position:center; }
接下来就是把CSS样式注入到CefSharp中,按照CefSharp的wiki描述,JavaScript脚本只能在V8Context
中执行,并且是在Frame级别执行。对于没有上下文的在Frame,一旦在Frame加载,就可以使用IFrame.ExecuteJavaScriptAsync
创建V8Context
。
在CefSharp中,IBrowser
和IFrame
对象用于向浏览器发送命令和在回调方法中获取状态信息,每个IBrowser
对象都有一个主IFrame
对象表示顶层frame(MainFrame),零个或多个IFrame对象表示子frame。
为了尽早把CSS样式注入到CefSharp中,可以在监听Browser.FrameLoadEnd
事件并执行脚本。
public MainWindow() { InitializeComponent(); Browser.FrameLoadEnd += Browser_FrameLoadEnd; } private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e) { if (e.Frame.IsMain) { //这里的style就是上一个代码片段中css样式的字符串 AddStyle(style); } } /// <summary> /// 添加CSS样式表 /// </summary> /// <param name="style">样式内容</param> public void AddStyle(string style) { if (string.IsNullOrEmpty(style)) return; StringBuilder sb = new StringBuilder(); sb.AppendLine("{let script = document.createElement('style');"); sb.Append("let node=document.createTextNode('").Append(style.Replace("n", string.Empty).Replace("r", string.Empty)).Append("');"); sb.AppendLine("script.appendChild(node);"); sb.AppendLine("let elements = document.getElementsByTagName('head');"); sb.AppendLine("if(elements.length>0){elements[0].appendChild(script);}"); sb.AppendLine("else if( (elements = document.getElementsByTagName('body')).length>0){elements[0].appendChild(script);}}"); Browser.GetMainFrame().ExecuteJavaScriptAsync(sb.ToString()); }
实现效果如下,滚动条的样式已被修改。在CefSharp的开发者工具中也可以看到注入的CSS样式。