cef中提供了一个内置的chome浏览器,对于C/S中使用B/S的方法提供了很大帮助,.net中 自带的webbrowser对IE浏览器有要求,如果客户端的IE版本较低,对于jquery中的方法部分不支持,所以cef就成为了B/S开发C/S的一个利器。
由于项目.net版本原因,用到的是CefSharp-cefsharp-47版本。
下载cef源码后,发现example下的dll有很多个,在网上查了资料后整理了一个大概项目中引用需要的dll文件
1) libcef.dll
2) icudtl.dat
3) devtools_resources.pak(这个必须要的,如果没有的话,页面上会出现好多类似代码的东西)
4) CefSharp.WinForms.dll
5) CefSharp.dll
6) CefSharp.Core.dll
7) CefSharp.BrowserSubprocess.exe
8) CefSharp.BrowserSubprocess.Core.dll
9) locales文件夹下的东西(都是类似于字符集编码的东西)
10)一些pak文件(这些文件是用来控制cef中的样式文件,如cef_100_percent.pak这个如果没有的话,html中的width=100%在窗体最大化的时候就不起作用)ChromiumWebBrowserm_chromeBrowser =null;
m_chromeBrowser= newChromiumWebBrowser("www.baidu.com");
注意ChromiumWebBrowser的构造方法只有一个,必须传入一个url,如果不需要就传""就行
load函数只能加载url,html串不行,得用下面的loadhtml
m_chromeBrowser.LoadHtml(htmlStr);
注意,这里的LoadHtml是采用的C#中的扩展方法写的。所谓的C#扩展方法就是相当于C#的一个语法炮弹,就是普通的静态类静态方法,需要把对象传入的。
这里必须usingCefSharp; using CefSharp.WinForms;如果只using了CefSharp.WinForms,那么new出来的ChromiumWebBrowser对象只能.出来Load方法,所有的扩展方法如LoadHtml都是无法点出来的。
m_chromeBrowser.LoadHtml("Helloworld","http://customrendering/");
两个参数,前面的那个是要显示在界面上的,后面的网址的作用暂时还没研究出来,应该是如果有服务器端的话,拼接服务器端的地址的(由于项目中并不是传统的服务器端模式,而是每个终端都是服务器加客户端 的模式,所以暂时没有研究,希望 大神指导下)
注意:网址的一定不能写成"",要不然会报错,直接程序就挂了,好像www.开头的也不行,只能用http://开头的网址用
1 html肯定是该咋写咋写了,主要是js,例如:
function test1()
{
varresult = winformObj.someFunction();
aler(result);
}
其中winformObj这个对象是由C#中定义的,所以就相当于这里用了js然后执行了一个C#的对象的方法。
2 定义winformObj
publicclassJavaScriptInteractionObj
{
[JavascriptIgnore](这个标签是cef自带的,现在还不知道有啥用)
publicChromiumWebBrowser m_chromeBrowser {get;set;}
[JavascriptIgnore]
publicvoidSetChromeBrowser(ChromiumWebBrowser b)
{
m_chromeBrowser = b;
}
//对应着js中调用的那个方法名称
public string someFunction(){
//...................
}
}
3 绑定对象(这个不是在JavaScriptInteractionObj类中,而是C#客户端中用到的页面进行绑定的)
m_jsInteractionObj = newJavaScriptInteractionObj();
m_jsInteractionObj.SetChromeBrowser(m_chromeBrowser);
// Register the JavaScriptInteractionObj class withJS
m_chromeBrowser.RegisterJsObject("winformObj",m_jsInteractionObj);
方式1. ExecuteScriptAsync 方法使用方式与 js 的 eval方法一样,异步执行,无返回值
// xxx为js的方法名称
wb.ExecuteScriptAsync("xxx()");
// 为 js 的变量jsVar赋值 'abc'
wb.ExecuteScriptAsync("jsVar='abc'");
(但为毛只能将js传入到webbrowser中呢,难道不能直接调用吗?加载的时候应该已经加载到了js了啊,难道没加载到js?貌似找不到相对路径哎,必须得弄成绝对路径,要不找不到
)
方式2.EvaluateScriptAsync 方法使用方式与 js 的 eval方法一样,异步执行,有返回值。
Task
// 等待js 方法执行完后,获取返回值
t.Wait();
// t.Result 是 CefSharp.JavascriptResponse 对象
// t.Result.Result 是一个 object 对象,来自js的 callTest2() 方法的返回值
if(t.Result.Result != null)
{
MessageBox.Show(t.Result.Result.ToString());
}
执行一段js脚本
m_chromeBrowser.LoadHtml("Helloworld","http://customrendering/");
varscript ="document.body.style.backgroundColor = 'red';";
m_chromeBrowser.ExecuteScriptAsync(script);
调用一段js方法的内容
m_chromeBrowser.LoadHtml("Helloworld","http://customrendering/");
StringBuilder sb =newStringBuilder();
sb.AppendLine("function tempFunction() {");
sb.AppendLine(" var w = window.innerWidth;");
sb.AppendLine(" var h = window.innerHeight;");
sb.AppendLine("");
sb.AppendLine(" return w*h;");
sb.AppendLine("}");
sb.AppendLine("tempFunction();");
vartask = m_chromeBrowser.EvaluateScriptAsync(sb.ToString());
task.ContinueWith(t =>
{
if (!t.IsFaulted)
{
var response = t.Result;
if ( response.Success ==true)
{
MessageBox.Show( response.Result.ToString() );
}
}
}, TaskScheduler.FromCurrentSynchronizationContext());
demo2
//Step 01: create a simple html page (include jquery so we have access to jsonobject
StringBuilder htmlPage =newStringBuilder();
htmlPage.AppendLine("");
htmlPage.AppendLine("");
htmlPage.AppendLine("
htmlPage.AppendLine("");
htmlPage.AppendLine("Hello world2");
htmlPage.AppendLine("");
//Step 02: Load the Page
m_chromeBrowser.LoadHtml(htmlPage.ToString(),"http://customrendering/");
//Step 03: Execute some ad-hoc JS that returns an object back to C#
StringBuilder sb =newStringBuilder();
sb.AppendLine("function tempFunction() {");
sb.AppendLine(" //create a JS object");
sb.AppendLine(" var person = {firstName:'John',lastName:'Maclaine', age:23, eyeColor:'blue'};");
sb.AppendLine("");
sb.AppendLine(" //Important: convert object to string before returning to C#");
sb.AppendLine(" return JSON.stringify(person);");
sb.AppendLine("}");
sb.AppendLine("tempFunction();");
vartask = m_chromeBrowser.EvaluateScriptAsync(sb.ToString());
task.ContinueWith(t =>
{
if(!t.IsFaulted)
{
// Step 04: Recieve value from JS
var response = t.Result;
if (response.Success ==true)
{
//Use JSON.net to convert to object;
MessageBox.Show(response.Result.ToString());
}
}
}, TaskScheduler.FromCurrentSynchronizationContext());
1 js执行时间,在cef中如果调用js中的某些方法,可能会出现有时能调用成功,有时调用失败的情况,调试后发现这完全就是还是拿C/S的思路去写B/S代码的错误。浏览器加载js都是要有时间的撒,在C#中要调用,必须得等js加载完全。f12后,发现了几个事件 formloadend loadstatechange等,最后用的是在cef的formloadend 事件中调用就好了
2 如果有两个窗口的pannel同时加载了cef,然后执行一个窗口的close,就抛一个空指针错误,这个调了好久,最后连着源码发现cef其实起了一个线程在不停的监控cef的状态,其中在CefSharp.WinForms.Internals.ControlExtensions中的方法
public static bool IsActiveControl(this Control control)
{
Control activeControl = control.FindForm().ActiveControl;
while (activeControl != null(这句话是自己加上的)
&& (activeControl is ContainerControl)
&& !Object.ReferenceEquals(control, activeControl))
{
var containerControl = activeControl as ContainerControl;
activeControl = containerControl.ActiveControl;
}
return Object.ReferenceEquals(control, activeControl);
}
3 调用js重复调用
js是在formloadend中写的,但写完js后猜想是又引起了cef的加载,所以不停的加载(上面说了cef起了一个线程在不停的看状态),所以如果在formloadend中写调用js的事件时,要记的调的时候+=,调完了后要-=,这样就不会重复调用了
6 漏了一个关键的信息,cef用完后必须调用cef.shutdown来结束其所依赖的exe进程,否则程序会出现进程关不掉的情况