-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
CefSharp中文帮助文档
1.1 cefsharp设置默认语言
1.2 cefSharp 服务器运行要求
1.3 cefsharp设置网页接受语言AcceptLanguage
1.4 cef设置userAgent
3.1 读取网页源代码
3.2 获取页面中的指定文件内容(.jpg,.js等)
3.3 过滤某些页面内容,例如图片或某些文字
3.4 文件进一步获取,获取完整内容
3.5 文件进一步获取,获取完整内容(优化,Content-Length不一致)
6.1 浏览器本身处理
6.2 需要关闭浏览器负载程序时操作
8.1 下载CefSharp master zip code文件编译报错
8.2 无法创建新的堆栈防护页面
9.1.你如何处理从.NET中的JavaScript方法?
9.2.如何调用Javascript方法返回的结果呢?
9.3.你如何暴露的.NET类为Javascript?
9.4.为什么我得到一个错误有关“无法加载文件或程序集CefSharp.Core.dll”或它的一个依赖。指定的模块找不到。“当试图运行基于我CefSharp的应用程序?它编译成功,但不运行?它运行我的开发机器上,虽然抛出一个异常,当我把它复制到另一台计算机?
9.5.为什么在Visual Studio WPF设计不是当我添加一个ChromiumWebBrowser我的应用程序工作?
9.6.我如何包括在目标应用程序的Visual Studio的C ++ 2012/2013再发行?
9.7.我如何重写的Javascript window.alert行动和相似?
9.8.在哪里CefSharp3二进制文件?
9.9.Windows XP / 2003支持
9.10.哪些文件,我需要包括,当我重新发布使用CefSharp的应用程序?
9.11.构建过程中不能复制CEF文件
9.12.为什么IndexedDB的返回QuotaExceededError?
9.13.你是如何处理在C#中Javascript事件?
cefsharp是不错的浏览器内核封装版本之一,默认语言是en-US,这个一直困扰着项目,项目好多处需修改,后来经多次尝试,才发现,原来设置默认语言这么简单。
Loacal 属性就是对CefSharp运行语言环境进行设置
var setting = new CefSharp.CefSettings();
// 设置语言
setting.Locale = "zh-CN";
CefSharp.Cef.Initialize(setting, true, false);
以上这段代码一定要在new ChromiumWebBrowser之前调用
.net framework 环境和 vc++ 2013 runtime (x86/x64)
什么是 cefsharp设置网页接受语言AcceptLanguage
1.设置浏览器的请求控制器
webView.RequestHandler = new RequestHandler();
2.新建RequestHandler类继承IRequestHandler接口,实现方法OnBeforeResourceLoad,新版本如果又变更但是整体思路不变,内部处理是一致的请见谅。
public bool OnBeforeResourceLoad(IWebBrowser browser, IRequestResponse requestResponse)
{
IDictionary<string, string> headers = requestResponse.Request.GetHeaders();
headers.Add("Accept-Language", "zh,zh-cn,zh-tw");
requestResponse.Request.SetHeaders(headers);
return false;
}
var setting = new CefSharp.CefSettings();
setting.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";
CefSharp.Cef.Initialize(setting, true, false);
所有配置:http://www.ericdlarson.com/misc/chrome_command_line_flags.html
样例参考:
var settings = new CefSettings();
settings.CefCommandLineArgs.Add("no-proxy-server", "1");
settings.CefCommandLineArgs.Add("proxy-server", "ProxyAddress");
Cef.Initialize(settings, true, true);
在页面加载完成后处理, 依赖最低环境 4.5.2
async void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e)
{
Log.WriteLog("browser_FrameLoadEnd:" + e.Url);
var result = await browser.GetSourceAsync();
}
如果想在4.0下环境操作需要使用。
var task = browser.GetSourceAsync();
task.Wait();
string content = task.Result;
A.首先需要对ChromiumWebBrowser 的 IRequestHandler RequestHandler进行实现。
B.需要对 IRequestHandler 的IResponseFilter IRequestHandler.GetResourceResponseFilter 方法进行重写。
C.需要写一个类实现 IResponseFilter 接口。
D.然后就可用在IResponseFilter 的
FilterStatus Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten) 方法中,读取指定内容的流了。
具体实现,参考 3.2 ,在最后的Filter方法中,对返回的dataOut不进行赋值或者,取到值,然后replace处理,返回其他数据,即可。
说明:由于很多文件无法获取到完整内容,再者具体文件内容在Filter里面进行了控制,而Fileter的内容依赖于IRequestHandler所以,外部只能操作Handler得到数据。 所以需要在,Filter和Hanlder类中,使用事件来传递具体的内容。代码如下。 Filter类如下:
public class TestImageFilter : IResponseFilter
{
public event Action<byte[]> NotifyData;
private int contentLength = 0;
private List<byte> dataAll = new List<byte>();
public void SetContentLength(int contentLength)
{
this.contentLength = contentLength;
}
public FilterStatus Filter(System.IO.Stream dataIn, out long dataInRead, System.IO.Stream dataOut, out long dataOutWritten)
{
try
{
if (dataIn == null)
{
dataInRead = 0;
dataOutWritten = 0;
return FilterStatus.Done;
}
dataInRead = dataIn.Length;
dataOutWritten = Math.Min(dataInRead, dataOut.Length);
dataIn.CopyTo(dataOut);
dataIn.Seek(0, SeekOrigin.Begin);
byte[] bs = new byte[dataIn.Length];
dataIn.Read(bs, 0, bs.Length);
dataAll.AddRange(bs);
if (dataAll.Count == this.contentLength)
{
// 通过这里进行通知
NotifyData(dataAll.ToArray());
return FilterStatus.Done;
}
else if (dataAll.Count < this.contentLength)
{
dataInRead = dataIn.Length;
dataOutWritten = dataIn.Length;
return FilterStatus.NeedMoreData;
}
else
{
return FilterStatus.Error;
}
}
catch (Exception ex)
{
dataInRead = dataIn.Length;
dataOutWritten = dataIn.Length;
return FilterStatus.Done;
}
}
public bool InitFilter()
{
return true;
}
}
Filter类有了,那我们如何知道数据流的具体长度呢?这就需要在Handler的实现的其他方法里面寻找了。
bool IRequestHandler.OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
//NOTE: You cannot modify the response, only the request
// You can now access the headers
//var headers = response.ResponseHeaders;
try
{
var content_length = int.Parse(response.ResponseHeaders["Content-Length"]);
if (this.filter != null)
{
this.filter.SetContentLength(content_length);
}
}
catch { }
return false;
}
private TestImageFilter filter = null;
public event Action<byte[]> NotifyData;
IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
var url = new Uri(request.Url);
if (url.AbsoluteUri.Contains("http://test.test.com/somehead?"))
{
this.filter = new TestImageFilter();
filter.NotifyData += filter_NotifyData;
return filter;
}
return null;
}
void filter_NotifyData(byte[] data)
{
if (NotifyData != null)
{
NotifyData(data);
}
}
此方法位IRequestHandler的一部分实现,通过实现函数:IRequestHandler.GetResourceResponseFilter得到资源文件的长度,然后长度传入Filter,在Filter中控制从而得到整个数据的真正长度。
由于,部分站点,返回数据是分片了的,即:不能通过,Content-Length的长度来判断,程序的流是否完成。
所以需要其他方式处理,即:单个http请求完成的时候,会调用Complete方法,所以可以在这里处理。
下面是测试代码:
Filter管理类
public class FilterManager
{
private static Dictionary<string, IResponseFilter> dataList = new Dictionary<string, IResponseFilter>();
public static IResponseFilter CreateFilter(string guid)
{
lock (dataList)
{
var filter = new TestImageFilter();
dataList.Add(guid, filter);
return filter;
}
}
public static IResponseFilter GetFileter(string guid)
{
lock (dataList)
{
return dataList[guid];
}
}
}
TestFilter类,对流进行合并
public class TestImageFilter : IResponseFilter
{
public List<byte> dataAll = new List<byte>();
public FilterStatus Filter(System.IO.Stream dataIn, out long dataInRead, System.IO.Stream dataOut, out long dataOutWritten)
{
try
{
if (dataIn == null || dataIn.Length == 0)
{
dataInRead = 0;
dataOutWritten = 0;
return FilterStatus.Done;
}
dataInRead = dataIn.Length;
dataOutWritten = Math.Min(dataInRead, dataOut.Length);
dataIn.CopyTo(dataOut);
dataIn.Seek(0, SeekOrigin.Begin);
byte[] bs = new byte[dataIn.Length];
dataIn.Read(bs, 0, bs.Length);
dataAll.AddRange(bs);
dataInRead = dataIn.Length;
dataOutWritten = dataIn.Length;
return FilterStatus.NeedMoreData;
}
catch (Exception ex)
{
dataInRead = dataIn.Length;
dataOutWritten = dataIn.Length;
return FilterStatus.Done;
}
}
public bool InitFilter()
{
return true;
}
}
最后是部分的。IRequestHandler实现代码
public class RequestHandler : IRequestHandler
{
// 略去代码 ...
public event Action<byte[]> NotifyMsg;
IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
var url = new Uri(request.Url);
if (url.AbsoluteUri.Contains("https://res.wx.qq.com/zh_CN/htmledition/v2/css/base/base2e4e03.css"))
{
var filter = FilterManager.CreateFilter(request.Identifier.ToString());
return filter;
}
return null;
}
void filter_NotifyData(byte[] data)
{
if (NotifyMsg != null)
{
NotifyMsg(data);
}
}
void IRequestHandler.OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)
{
if (request.Url.Contains("https://res.wx.qq.com/zh_CN/htmledition/v2/css/base/base2e4e03.css"))
{
var filter = FilterManager.GetFileter(request.Identifier.ToString()) as TestImageFilter;
filter_NotifyData(filter.dataAll.ToArray());
}
}
}
var cookieManager = CefSharp.Cef.GetGlobalCookieManager();
await cookieManager.SetCookieAsync("http://" + domain, new CefSharp.Cookie(
{
Domain = domain,
Name = name,
Value = value,
Expires = DateTime.MinValue
});
建立Cookie读取对象,继承接口 ICookieVisitor
public class CookieVisitor : CefSharp.ICookieVisitor
{
public event Action<CefSharp.Cookie> SendCookie;
public bool Visit(CefSharp.Cookie cookie, int count, int total, ref bool deleteCookie)
{
deleteCookie = false;
if (SendCookie != null)
{
SendCookie(cookie);
}
return true;
}
}
在browser事件中进行处理
private void browser_FrameLoadEnd(object sender, CefSharp.FrameLoadEndEventArgs e)
{
var cookieManager = CefSharp.Cef.GetGlobalCookieManager();
CookieVisitor visitor = new CookieVisitor();
visitor.SendCookie += visitor_SendCookie;
cookieManager.VisitAllCookies(visitor);
}
/// 回调事件
private void visitor_SendCookie(CefSharp.Cookie obj)
{
cookies += obj.Domain.TrimStart('.') + "^" + obj.Name + "^" + obj.Value + "$";
}
browser.GetBrowser().MainFrame.ExecuteJavaScriptAsync("document.getElementById('testid').click();");
browser.GetBrowser().MainFrame.ExecuteJavaScriptAsync("document.getElementById('testid2').value='123'");
string script = "if(document.getElementById('img_out_10000')){ document.getElementById('img_out_10000').click(); }";
var list = browser.GetBrowser().GetFrameNames();
if (list.Count > 1)
{
browser.GetBrowser().GetFrame(list[1]).ExecuteJavaScriptAsync(script);
}
参见本文档:9.3
static ChromiumWebBrowser()
{
if (CefSharpSettings.ShutdownOnExit)
{
Application.ApplicationExit += OnApplicationExit;
}
}
private static void OnApplicationExit(object sender, EventArgs e)
{
Cef.Shutdown();
}
try
{
browser.CloseDevTools();
browser.GetBrowser().CloseBrowser(true);
}
catch { }
try
{
if (browser != null)
{
browser.Dispose();
Cef.Shutdown();
}
}
catch { }
下载地址:https://codeload.github.com/cefsharp/CefSharp/zip/master
错误提示:
由于编译路径存在中文导致。
可能是由于 进程“ CefSharp.BrowserSubprocess.exe ”没有正常结束掉,一直占用内存增加,直到...
快速TOC常见问题解答
本FAQ〜10个项目。它试图展示一些很酷的CefSharp功能和一些最常见的问题的的。
更多的提示看打成FAQ-能的问题越来越多!
1.你如何称呼从.NET JavaScript方法?
2.如何调用Javascript方法返回的结果呢?
3.你如何暴露的.NET类为Javascript?
4.“无法加载文件或程序集CefSharp.Core.dll”或它的一个依赖。
5.为什么在Visual Studio WPF设计不是当我添加一个ChromiumWebBrowser我的应用程序工作?
6.我如何包括在目标应用程序的Visual Studio的C ++ 2012/2013再发行?
7.我如何重写的Javascript window.alert行动和相似?
8.在哪里CefSharp3二进制文件?
9.Windows XP / 2003支持?
10.哪些文件,我需要包括,当我重新发布使用CefSharp的应用程序?
11.构建过程中不能复制CEF文件
12.为什么IndexedDB的返回QuotaExceededError?
13.你是如何处理在C#中Javascript事件?
简单的代码可能是这个样子:
var script = string.Format("document.body.style.background = '{0}'", colors[color_index++]);if (color_index >= colors.Length)
{
color_index = 0;
}
browser.GetMainFrame().ExecuteJavaScriptAsync(script);
不幸的是加载DOM之前OnFrameLoadStart被调用,所以你需要使用如下之一:FrameLoadEnd / LoadingStateChanged / IRenderProcessMessageHandler.OnContextCreated。下面是几个例子
browser.RenderProcessMessageHandler = new RenderProcessMessageHandler();
public class RenderProcessMessageHandler : IRenderProcessMessageHandler
{
// Wait for the underlying `Javascript Context` to be created, this is only called for the main frame.
// If the page has no javascript, no context will be created.
void IRenderProcessMessageHandler.OnContextCreated(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
const string script = "document.addEventListener('DOMContentLoaded', function(){ alert('DomLoaded'); });";
frame.ExecuteJavaScriptAsync(script);
}
}
//Wait for the page to finish loading (all resources will have been loaded, rendering is likely still happening)
browser.LoadingStateChanged += (sender, args) =>
{
//Wait for the Page to finish loading
if (args.IsLoading == false)
{
browser.ExecuteJavaScriptAsync("alert('All Resources Have Loaded');");
}
}
//Wait for the MainFrame to finish loading
browser.FrameLoadEnd += (sender, args) =>
{
//Wait for the MainFrame to finish loading
if(args.Frame.IsMain)
{
args.Frame.ExecuteJavaScriptAsync("alert('MainFrame finished loading');");
}
};
注意:脚本是在Frame级别执行,永远页具有至少一个帧(MainFrame)。该IWebBrowser.ExecuteScriptAsync扩展方法是为了向下兼容,你可以使用它作为一个快捷方式到主框架上执行JS。
如果您需要评估代码,返回一个值,使用Task EvaluateScriptAsync(string script, TimeSpan? timeout)方法。 JavaScript代码是异步执行的,因此使用.NET Task类返回一个响应,其中包含错误消息,结果和一个成功(布尔)标志。
// Get Document Height
var task = frame.EvaluateScriptAsync("(function() { var body = document.body, html = document.documentElement; return Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ); })();", null);
task.ContinueWith(t =>
{
if (!t.IsFaulted)
{
var response = t.Result;
EvaluateJavaScriptResult = response.Success ? (response.Result ?? "null") : response.Message;
}
}, TaskScheduler.FromCurrentSynchronizationContext());
有关更详细的例子看看这个要点
脚本是在帧级别执行,永远页至少有一个Frame(MainFrame)
只有微不足道的值可以返回(如int,布尔,字符串等) - 而不是一个复杂的(用户定义的)类型,你自己已经定义。这是因为没有(易)的方式来揭露一个随机的Javascript对象到.NET世界,至少不是今天。然而,一个可行的方法是把你想返回到你的.NET代码到一个JSON字符串使用JavaScript JSON.toStringify()方法,而该字符串返回到你的.NET代码的JavaScript对象。然后,你可以解码该字符串与类似JSON.net .NET对象。看到这个MSDN链接了解更多信息。 (https://msdn.microsoft.com/en-us/library/ie/cc836459(v=vs.94).aspx)
像这样:
public class BoundObject
{
public string MyProperty { get; set; }
public void MyMethod()
{
// Do something really cool here.
}
}
// ...
// After your ChromiumWebBrowser has been created
browser.RegisterJsObject("bound", new BoundObject());
In the actual JS code, you would use the object like this:
bound.myProperty; // use this syntax to access the property
bound.myMethod(); // use this to call the method.
请注意:
默认情况下的方法和属性就变成驼峰,即第一个字母是小写,使其使用更与你的JavaScript代码的其余部分一起顺利。对于39.0.1和更高,这是可选的,可以使用camelCaseJavascriptNames布尔参数指定此行为
RegisterJsObject应该直接叫你创建ChromiumWebBrowser的实例后。内部CEF浏览器实例已初始化后续调用后RegisterJsObject将抛出一个异常(有没有飞约束力尚未RegisterJsObject见#602)
复杂的对象都支持属性,所以你现在可以做bound.subObject.myFunction()和bound.subObject.myProperty = 1。
对于功能复杂对象的支持仅限于琐碎的值(如int,布尔,字符串等)
从CefSharp1那些升级全球CEF.RegisterJsObject已被删除,现在你必须直接使用方法上ChromiumWebBrowser绑定。
4.为什么我得到一个错误有关“无法加载文件或程序集CefSharp.Core.dll”或它的一个依赖。指定的模块找不到。“当试图运行基于我CefSharp的应用程序?它编译成功,但不运行?它运行我的开发机器上,虽然抛出一个异常,当我把它复制到另一台计算机?
这是一个常见的错误,通常是下列之一
1、VC ++ 2012/2013再发行组件包需要以非开发机器上运行CefSharp。请参阅以下FAQ#6获取更多信息。您可以包括所需的DLL作为应用程序的一部分。
2、不是所有的依赖关系存在于执行的文件夹。 CefSharp包括非托管的dll和资源,这些是通过当您安装的NuGet包,它们包含在你的项目中的两个.props文件复制到文件夹执行。见所需文件的列表的下方,确保所需的文件都存在。
3、你可以通过安装程序打包为分发的应用程序,它不会在目标机器上运行。安装不包括在默认情况下的非托管资源,你需要手动添加。对于ClickOnce的,请参阅#1314对一些指针和解决方案的其他用户纷纷拿出。
所需文件的列表可以在这里找到:输出文件说明(再分配)
注:如果您在初始化XAML的WPF控件时得到一个FileNotFoundException异常这也适用。
这是不幸的,那CefSharp是用C ++编写的代码,这反过来又引用CEF DLL的事实的结果:s。这种情况是不是这样由Visual Studio设计很好的支持。本次论坛主题解释这一点,并还给出了可能的解决方法。我认为(不幸)的最简单的解决方法是只需接受事实,这是不容易的支持,只是住在一起,但也有,如果你真的觉得你需要其他方法。
CefSharp需要VC ++运行时。你必须安装/包括这与你的应用程序的几个选项:
你可以在你希望运行CefSharp基于应用程序的每台计算机上安装VC ++。一旦安装更新就可以通过Windows Update进行管理。
您可以设置在Visual Studio C ++再分发作为安装程序的先决条件(即的ClickOnce或WiX的工具集)
通过复制到您的项目在此文件夹(只有当你安装了Visual Studio中的匹配版本存在)的内容:
#对于VC ++ 2012(86)
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\redist\x86\Microsoft.VC110.CRT
#对于VC ++ 2012(64)
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\redist\x64\Microsoft.VC110.CRT
#对于VC ++ 2013(86)
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\x86\Microsoft.VC120.CRT
#对于VC ++ 2013(64)
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\x64\Microsoft.VC120.CRT
随着第三方法,你将不再需要为前提的Visual C ++运行时2012/2013文件安装到客户端。就目前的计划是留在VC2013官方CefSharp二进制版本。可行时,我们可能会切换到VC2015。如果你从源代码构建自己的你部署的过程中必须与您构建环境。对于官方的NuGet版本的详细信息请参见发布分支表。
欲了解更多信息,请参阅重新分发的Visual C ++文件MSDN上。要下载,请访问Visual Studio的C ++ 2012/2013再发行
注意从源代码构建确保你在Release模式部署到没有安装Visual Studio机时编译。 VISUAL C ++使用一套不同的调试和发布版本的运行时库。调试运行时库仅安装有Visual Studio中。如果你使用他们已经建在释放模式官方的NuGet软件包,您可以随后建立在调试模式下您的应用程序,因为只有在Visual C ++项目需要在Release模式下进行编译。
该ChromiumWebBrowser控件提供了一个名为JsDialogHandler属性。该属性可被设置为一类你的,它可以用于覆盖这些对话框的行为。
CefSharp3被释放的NuGet包。 请参阅https://github.com/cefsharp/CefSharp/blob/master/README.md#nuget-packages最新的稳定和预发布版本。
对于使用的NuGet包一个很简单的例子项目,请参阅CefSharp.MinimalExample库。克隆它/如果你想要的CefSharp3如何使用一个非常小的和简单的例子下载源。
请注意:目标平台
使用这些包时,您必须选择x86或x64。如果选择值为anycpu的神奇的NuGet不会目前的工作。见步骤来这里配置的解决方案。
我们不再支持Windows XP / 2003。官方的NuGet包不能在Windows XP / 2003进行测试。你可以使用针对VC ++ 2013新版本有一些运气(有一个已知的问题与VC ++ 2012包)。 (请记住,CefSharp.Example *项目都是使用.NET 4.5,所以你必须重新瞄准他们和更新相应的代码,你应该想使用提供的例子编译)。
请不要创建与Windows XP的新问题。
下面https://github.com/cefsharp/CefSharp/wiki/Windows-XP-No-Longer-Supported
维基页面可能是有用的,可以通过一个帐户GitHub的任何人进行编辑,可以随意你认为任何信息有助于可能是有用的。
请参阅:输出文件说明(再分配)
有时生成过程不能复制CEF文件和重试了很多次,终于失败。这发生在CefSharp.BrowserSubprocess.exe即使应用程序被关闭仍在运行。 解决方案是使用即任务管理器手动终止CefSharp.BrowserSubprocess.exe。
当使用IndexedDB的工作,你必须设置CefSettings CachePath到当前用户具有写入权限的目录。在大多数情况下,你可以使用这样的代码来创建一个缓存目录和初始化过程中通过设置Initialize():
// On Win7 this will create a directory in AppData.
var cache = System.IO.Path.Combine(Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), System.IO.Path.Combine("MyApplication","cache"));
if (!System.IO.Directory.Exists (cache))
System.IO.Directory.CreateDirectory (cache);
// Set the CachePath during initialization.
var settings = new CefSettings(){CachePath = cache};
Cef.Initialize (settings);
public class BoundObject
{
public void OnFrameLoadEnd (object sender, FrameLoadEndEventArgs e)
{
if(e.Frame.IsMain)
{
browser.ExecuteScriptAsync(@"
document.body.onmouseup = function()
{
bound.onSelected(window.getSelection().toString());
}");
}
}
public void OnSelected(string selected)
{
MessageBox.Show("The user selected some text [" + selected + "]");
}
}
// ...
// After your ChromiumWebBrowser has been instantiated (for WPF directly after `InitializeComponent();` in the control constructor).var obj = new BoundObject();
browser.RegisterJsObject("bound", obj);
browser.FrameLoadEnd += obj.OnFrameLoadEnd ;
请注意:
RegisterJsObject应该直接创建ChromiumWebBrowser的一个实例后调用
“结合”是将作为在网页上运行的任何的JS脚本访问的顶层对象创建的对象的名称。你可以使用任何你喜欢的,但确保它不会与现有JS对象发生冲突,那名在C#和JS相匹配。
该样品注入JS代码插入即时使用FrameLoadEnd事件的网页。如果你有网页的控制,你可以简单地添加JS代码到网页。
我们称一个字符串参数的OnSelected C#方法。您可以使用任意数量的参数,或者没有,但他们必须是原始类型。
确保你施放复杂的JS对象字符串或他们路过时把它们转换成JSON。
由于CefSharp将寻求通过其名称OnSelected的方法,确保您的混淆器不会在别的方法重命名为,否则将不被执行。
http://www.cnblogs.com/TianFang/p/4658151.html
文档仅供参考,错误之处望修改,或指正