• cefsharp文档


    原文链接:https://github.com/cefsharp/CefSharp/wiki/CefSharp中文帮助文档#a1_1

    CefSharp中文帮助文档

     

    目录

    基础知识

    1.1 cefsharp设置默认语言

    1.2 cefSharp 服务器运行要求

    1.3 cefsharp设置网页接受语言AcceptLanguage

    1.4 cef设置userAgent

    2、配置管理

    2.1、CommandLine配置

    3、请求流程处理

    3.1 读取网页源代码

    3.2 获取页面中的指定文件内容(.jpg,.js等)

    3.3 过滤某些页面内容,例如图片或某些文字

    3.4 文件进一步获取,获取完整内容

    3.5 文件进一步获取,获取完整内容(优化,Content-Length不一致)

    4、Cookie处理

    4.1 设置cookie

    4.2 读取cookie

    5、Js处理

    5.1 基本的同(异)步js操作

    5.2 其他Frame操作

    5.3 js回调,C#方法

    6、资源清理

    6.1 浏览器本身处理

    6.2 需要关闭浏览器负载程序时操作

    7、扩展功能

    8、常见错误

    8.1 下载CefSharp master zip code文件编译报错

    8.2 无法创建新的堆栈防护页面

    8.3 结束浏览器后,CefSharp.BrowserSubprocess.exe进行无法结束

    9、GitHub---Wiki(部分内容使用了Google进行翻译)

    快速FAQ TOC 英文版本

    1. 如何使用.NET 调用 JavaScript方法?

    2. 如何获取 Javascript 方法返回的结果?

    3. 如何暴露.NET类,提供给Javascript?

    4. 为什么我得到一个错误有关“无法加载文件或程序集 CefSharp.Core.dll”或它的一个依赖。指定的模块找不到。“当试图运行基于我CefSharp的应用程序?它编译成功,但不运行?它运行我的开发机器上,虽然抛出一个异常,当我把它复制到另一台计算机?

    5. 为什么当我将 ChromiumWebBrowser 添加到我的应用程序时,Visual Studio WPF设计器不起作用?

    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事件?

    14. 如何实现 WinForms 拖放?

    10、参考网址

    11、其他


    基础知识

    1.1 cefsharp设置默认语言

    cefsharp是不错的浏览器内核封装版本之一,默认语言是en-US,这个一直困扰着项目,项目好多处需修改,后来经多次尝试,才发现,原来设置默认语言这么简单。 Loacal 属性就是对CefSharp运行语言环境进行设置
    var setting = new CefSharp.CefSettings();

    // 设置语言
    setting.Locale = "zh-CN";
    CefSharp.Cef.Initialize(setting, true, false); 以上这段代码一定要在new ChromiumWebBrowser之前调用

    1.  
      public App()
    2.  
      {
    3.  
      //Monitor parent process exit and close subprocesses if parent process exits first
    4.  
      //This will at some point in the future becomes the default
    5.  
      CefSharpSettings.SubprocessExitIfParentProcessClosed = true;
    6.  
       
    7.  
      var settings = new CefSettings()
    8.  
      {
    9.  
      AcceptLanguageList = "zh-CN",
    10.  
      //By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist data
    11.  
      CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\Cache")
    12.  
      };
    13.  
       
    14.  
      //Example of setting a command line argument
    15.  
      //Enables WebRTC
    16.  
      settings.CefCommandLineArgs.Add("enable-media-stream", "1");
    17.  
       
    18.  
      //Perform dependency check to make sure all relevant resources are in our output directory.
    19.  
      Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);
    20.  
      }

    1.2 cefSharp 服务器运行要求

    .net framework 环境和 vc++ 2013 runtime (x86/x64)

    1.3 cefsharp设置网页接受语言AcceptLanguage

    什么是 cefsharp设置网页接受语言AcceptLanguage
    1.设置浏览器的请求控制器
     webView.RequestHandler = new RequestHandler(); 
    2.新建RequestHandler类继承IRequestHandler接口,实现方法OnBeforeResourceLoad,新版本如果又变更但是整体思路不变,内部处理是一致的请见谅。

    1.  
      public bool OnBeforeResourceLoad(IWebBrowser browser, IRequestResponse requestResponse)
    2.  
      {
    3.  
      IDictionary<string, string> headers = requestResponse.Request.GetHeaders();
    4.  
      headers.Add("Accept-Language", "zh,zh-cn,zh-tw");
    5.  
      requestResponse.Request.SetHeaders(headers);
    6.  
      return false;
    7.  
      }

    1.4 cef设置userAgent

    1.  
      var setting = new CefSharp.CefSettings();
    2.  
      setting.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";
    3.  
      CefSharp.Cef.Initialize(setting, true, false);

    2、配置管理

    2.1、CommandLine配置

    所有配置:http://peter.sh/experiments/chromium-command-line-switches/
    样例参考:

    1.  
      var settings = new CefSettings();
    2.  
      settings.CefCommandLineArgs.Add("no-proxy-server", "1");
    3.  
      settings.CefCommandLineArgs.Add("proxy-server", "ProxyAddress");
    4.  
      Cef.Initialize(settings, true, true);

    3、请求流程处理

    3.1 读取网页源代码

    在页面加载完成后处理, 依赖最低环境 4.5.2

    1.  
      async void browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e)
    2.  
      {
    3.  
      Log.WriteLog("browser_FrameLoadEnd:" + e.Url);
    4.  
       
    5.  
      var result = await browser.GetSourceAsync();
    6.  
      }

    如果想在4.0下环境操作需要使用。

    1.  
       var task = browser.GetSourceAsync();
    2.  
      task.Wait();
    3.  
      string content = task.Result;

    3.2 获取页面中的指定文件内容(.jpg,.js等)

    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.3 过滤某些页面内容,例如图片或某些文字

    具体实现,参考 3.2 ,在最后的Filter方法中,对返回的dataOut不进行赋值或者,取到值,然后replace处理,返回其他数据,即可。

    3.4 文件进一步获取,获取完整内容

    说明:由于很多文件无法获取到完整内容,再者具体文件内容在Filter里面进行了控制,而Fileter的内容依赖于IRequestHandler所以,外部只能操作Handler得到数据。 所以需要在,Filter和Hanlder类中,使用事件来传递具体的内容。代码如下。 Filter类如下:

    1.  
      public class TestImageFilter : IResponseFilter
    2.  
      {
    3.  
      public event Action<byte[]> NotifyData;
    4.  
      private int contentLength = 0;
    5.  
      private List<byte> dataAll = new List<byte>();
    6.  
       
    7.  
      public void SetContentLength(int contentLength)
    8.  
      {
    9.  
      this.contentLength = contentLength;
    10.  
      }
    11.  
       
    12.  
      public FilterStatus Filter(System.IO.Stream dataIn, out long dataInRead, System.IO.Stream dataOut, out long dataOutWritten)
    13.  
      {
    14.  
      try
    15.  
      {
    16.  
      if (dataIn == null)
    17.  
      {
    18.  
      dataInRead = 0;
    19.  
      dataOutWritten = 0;
    20.  
       
    21.  
      return FilterStatus.Done;
    22.  
      }
    23.  
       
    24.  
      dataInRead = dataIn.Length;
    25.  
      dataOutWritten = Math.Min(dataInRead, dataOut.Length);
    26.  
       
    27.  
      dataIn.CopyTo(dataOut);
    28.  
      dataIn.Seek(0, SeekOrigin.Begin);
    29.  
      byte[] bs = new byte[dataIn.Length];
    30.  
      dataIn.Read(bs, 0, bs.Length);
    31.  
      dataAll.AddRange(bs);
    32.  
       
    33.  
      if (dataAll.Count == this.contentLength)
    34.  
      {
    35.  
      // 通过这里进行通知
    36.  
      NotifyData(dataAll.ToArray());
    37.  
       
    38.  
      return FilterStatus.Done;
    39.  
      }
    40.  
      else if (dataAll.Count < this.contentLength)
    41.  
      {
    42.  
      dataInRead = dataIn.Length;
    43.  
      dataOutWritten = dataIn.Length;
    44.  
       
    45.  
      return FilterStatus.NeedMoreData;
    46.  
      }
    47.  
      else
    48.  
      {
    49.  
      return FilterStatus.Error;
    50.  
      }
    51.  
      }
    52.  
      catch (Exception ex)
    53.  
      {
    54.  
      dataInRead = dataIn.Length;
    55.  
      dataOutWritten = dataIn.Length;
    56.  
       
    57.  
      return FilterStatus.Done;
    58.  
      }
    59.  
      }
    60.  
       
    61.  
      public bool InitFilter()
    62.  
      {
    63.  
      return true;
    64.  
      }
    65.  
      }

    Filter类有了,那我们如何知道数据流的具体长度呢?这就需要在Handler的实现的其他方法里面寻找了。

    1.  
      bool IRequestHandler.OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    2.  
      {
    3.  
      //NOTE: You cannot modify the response, only the request
    4.  
      // You can now access the headers
    5.  
      //var headers = response.ResponseHeaders;
    6.  
      try
    7.  
      {
    8.  
      var content_length = int.Parse(response.ResponseHeaders["Content-Length"]);
    9.  
      if (this.filter != null)
    10.  
      {
    11.  
      this.filter.SetContentLength(content_length);
    12.  
      }
    13.  
      }
    14.  
      catch { }
    15.  
      return false;
    16.  
      }
    17.  
       
    18.  
      private TestImageFilter filter = null;
    19.  
      public event Action<byte[]> NotifyData;
    20.  
       
    21.  
      IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    22.  
      {
    23.  
      var url = new Uri(request.Url);
    24.  
      if (url.AbsoluteUri.Contains("http://test.test.com/somehead?"))
    25.  
      {
    26.  
      this.filter = new TestImageFilter();
    27.  
      filter.NotifyData += filter_NotifyData;
    28.  
       
    29.  
      return filter;
    30.  
      }
    31.  
       
    32.  
      return null;
    33.  
      }
    34.  
       
    35.  
      void filter_NotifyData(byte[] data)
    36.  
      {
    37.  
      if (NotifyData != null)
    38.  
      {
    39.  
      NotifyData(data);
    40.  
      }
    41.  
      }

    此方法位IRequestHandler的一部分实现,通过实现函数:IRequestHandler.GetResourceResponseFilter得到资源文件的长度,然后长度传入Filter,在Filter中控制从而得到整个数据的真正长度。

    3.5 文件进一步获取,获取完整内容(优化,Content-Length不一致)

    由于,部分站点,返回数据是分片了的,即:不能通过,Content-Length的长度来判断,程序的流是否完成。
    所以需要其他方式处理,即:单个http请求完成的时候,会调用Complete方法,所以可以在这里处理。
    下面是测试代码: Filter管理类

    1.  
      public class FilterManager
    2.  
      {
    3.  
      private static Dictionary<string, IResponseFilter> dataList = new Dictionary<string, IResponseFilter>();
    4.  
       
    5.  
      public static IResponseFilter CreateFilter(string guid)
    6.  
      {
    7.  
      lock (dataList)
    8.  
      {
    9.  
      var filter = new TestImageFilter();
    10.  
      dataList.Add(guid, filter);
    11.  
       
    12.  
      return filter;
    13.  
      }
    14.  
      }
    15.  
       
    16.  
      public static IResponseFilter GetFileter(string guid)
    17.  
      {
    18.  
      lock (dataList)
    19.  
      {
    20.  
      return dataList[guid];
    21.  
      }
    22.  
      }
    23.  
      }

    TestFilter类,对流进行合并

    1.  
      public class TestImageFilter : IResponseFilter
    2.  
      {
    3.  
      public List<byte> dataAll = new List<byte>();
    4.  
       
    5.  
      public FilterStatus Filter(System.IO.Stream dataIn, out long dataInRead, System.IO.Stream dataOut, out long dataOutWritten)
    6.  
      {
    7.  
      try
    8.  
      {
    9.  
      if (dataIn == null || dataIn.Length == 0)
    10.  
      {
    11.  
      dataInRead = 0;
    12.  
      dataOutWritten = 0;
    13.  
       
    14.  
      return FilterStatus.Done;
    15.  
      }
    16.  
       
    17.  
      dataInRead = dataIn.Length;
    18.  
      dataOutWritten = Math.Min(dataInRead, dataOut.Length);
    19.  
       
    20.  
      dataIn.CopyTo(dataOut);
    21.  
      dataIn.Seek(0, SeekOrigin.Begin);
    22.  
      byte[] bs = new byte[dataIn.Length];
    23.  
      dataIn.Read(bs, 0, bs.Length);
    24.  
      dataAll.AddRange(bs);
    25.  
       
    26.  
      dataInRead = dataIn.Length;
    27.  
      dataOutWritten = dataIn.Length;
    28.  
       
    29.  
      return FilterStatus.NeedMoreData;
    30.  
      }
    31.  
      catch (Exception ex)
    32.  
      {
    33.  
      dataInRead = dataIn.Length;
    34.  
      dataOutWritten = dataIn.Length;
    35.  
       
    36.  
      return FilterStatus.Done;
    37.  
      }
    38.  
      }
    39.  
       
    40.  
      public bool InitFilter()
    41.  
      {
    42.  
      return true;
    43.  
      }
    44.  
      }

    最后是部分的。IRequestHandler实现代码

    1.  
      public class RequestHandler : IRequestHandler
    2.  
      {
    3.  
      // 略去代码 ...
    4.  
       
    5.  
      public event Action<byte[]> NotifyMsg;
    6.  
       
    7.  
      IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    8.  
      {
    9.  
      var url = new Uri(request.Url);
    10.  
      if (url.AbsoluteUri.Contains("https://res.wx.qq.com/zh_CN/htmledition/v2/css/base/base2e4e03.css"))
    11.  
      {
    12.  
      var filter = FilterManager.CreateFilter(request.Identifier.ToString());
    13.  
       
    14.  
      return filter;
    15.  
      }
    16.  
       
    17.  
      return null;
    18.  
      }
    19.  
       
    20.  
      void filter_NotifyData(byte[] data)
    21.  
      {
    22.  
      if (NotifyMsg != null)
    23.  
      {
    24.  
      NotifyMsg(data);
    25.  
      }
    26.  
      }
    27.  
       
    28.  
      void IRequestHandler.OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)
    29.  
      {
    30.  
      if (request.Url.Contains("https://res.wx.qq.com/zh_CN/htmledition/v2/css/base/base2e4e03.css"))
    31.  
      {
    32.  
      var filter = FilterManager.GetFileter(request.Identifier.ToString()) as TestImageFilter;
    33.  
       
    34.  
      filter_NotifyData(filter.dataAll.ToArray());
    35.  
      }
    36.  
      }
    37.  
      }

    4、Cookie处理

    4.1 设置cookie

    1.  
      var cookieManager = CefSharp.Cef.GetGlobalCookieManager();
    2.  
      await cookieManager.SetCookieAsync("http://" + domain, new CefSharp.Cookie()
    3.  
      {
    4.  
      Domain = domain,
    5.  
      Name = name,
    6.  
      Value = value,
    7.  
      Expires = DateTime.MinValue
    8.  
      });

    4.2 读取cookie

    建立Cookie读取对象,继承接口 ICookieVisitor

    1.  
      public class CookieVisitor : CefSharp.ICookieVisitor
    2.  
      {
    3.  
      public event Action<CefSharp.Cookie> SendCookie;
    4.  
      public bool Visit(CefSharp.Cookie cookie, int count, int total, ref bool deleteCookie)
    5.  
      {
    6.  
      deleteCookie = false;
    7.  
      if (SendCookie != null)
    8.  
      {
    9.  
      SendCookie(cookie);
    10.  
      }
    11.  
       
    12.  
      return true;
    13.  
      }
    14.  
      }

    在browser事件中进行处理

    1.  
      private void browser_FrameLoadEnd(object sender, CefSharp.FrameLoadEndEventArgs e)
    2.  
      {
    3.  
      var cookieManager = CefSharp.Cef.GetGlobalCookieManager();
    4.  
       
    5.  
      CookieVisitor visitor = new CookieVisitor();
    6.  
      visitor.SendCookie += visitor_SendCookie;
    7.  
      cookieManager.VisitAllCookies(visitor);
    8.  
      }

    /// 回调事件

    1.  
      private void visitor_SendCookie(CefSharp.Cookie obj)
    2.  
      {
    3.  
      cookies += obj.Domain.TrimStart('.') + "^" + obj.Name + "^" + obj.Value + "$";
    4.  
      }

    5、Js处理

    5.1 基本的同(异)步js操作

    1.  
      browser.GetBrowser().MainFrame.ExecuteJavaScriptAsync("document.getElementById('testid').click();");
    2.  
      browser.GetBrowser().MainFrame.ExecuteJavaScriptAsync("document.getElementById('testid2').value='123'");

    5.2 其他Frame操作

    1.  
      string script = "if(document.getElementById('img_out_10000')){ document.getElementById('img_out_10000').click(); }";
    2.  
      var list = browser.GetBrowser().GetFrameNames();
    3.  
      if (list.Count > 1)
    4.  
      {
    5.  
      browser.GetBrowser().GetFrame(list[1]).ExecuteJavaScriptAsync(script);
    6.  
      }

    5.3 js回调,C#方法

    参见本文档:9.3

    6、资源清理

    6.1 浏览器本身处理

    1.  
      static ChromiumWebBrowser()
    2.  
      {
    3.  
      if (CefSharpSettings.ShutdownOnExit)
    4.  
      {
    5.  
      Application.ApplicationExit += OnApplicationExit;
    6.  
      }
    7.  
      }
    8.  
       
    9.  
      private static void OnApplicationExit(object sender, EventArgs e)
    10.  
      {
    11.  
      Cef.Shutdown();
    12.  
      }

    6.2 需要关闭浏览器负载程序时操作

    1.  
      try
    2.  
      {
    3.  
      browser.CloseDevTools();
    4.  
      browser.GetBrowser().CloseBrowser(true);
    5.  
      }
    6.  
      catch { }
    7.  
       
    8.  
      try
    9.  
      {
    10.  
      if (browser != null)
    11.  
      {
    12.  
      browser.Dispose();
    13.  
      Cef.Shutdown();
    14.  
      }
    15.  
      }
    16.  
      catch { }

    7、扩展功能

    8、常见错误

    8.1 下载CefSharp master zip code文件编译报错

    下载地址:https://codeload.github.com/cefsharp/CefSharp/zip/master
    错误提示:

    由于编译路径存在中文导致。

    8.2 无法创建新的堆栈防护页面

    可能是由于 进程“ CefSharp.BrowserSubprocess.exe ”没有正常结束掉,一直占用内存增加,直到...

    8.3 结束浏览器后,CefSharp.BrowserSubprocess.exe进行无法结束

    需要确保,创建浏览器的线程和调用Cef.ShutDown();的线程确保在同一个线程中进行操作。 如果是主线程创建。关闭程序后BrowserSubprocess进程可以直接退出。 如果是非主线程,需要在创建浏览器,即:把浏览器绑定到控件的线程,调用shutdown方法。

    9、GitHub---Wiki(部分内容使用了Google进行翻译)

    本文档的大部分将被替换为新的 一般使用指南 - 必须阅读!

    快速FAQ TOC 英文版本

    本FAQ〜10项。尝试列出一些很酷的CefSharp特性和一些最常见的问题的的。

    有关更多提示,请查看不断增加的问题列表faq-able!

    1. 如何使用.NET 调用 JavaScript方法?
    2. 如何获取 Javascript 方法返回的结果呢?
    3. 如何暴露.NET类,提供给Javascript?
    4. “无法加载文件或程序集 CefSharp.Core.dll ”或它的一个依赖。
    5. 为什么当我将 ChromiumWebBrowser 添加到我的应用程序时,Visual Studio WPF设计器不起作用?
    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事件?
    14. 如何实现 WinForms 拖放?

    1. 如何使用.NET 调用 JavaScript方法?

    简单代码可能看起来像这样:

    1.  
      var script = string.Format("document.body.style.background = '{0}'", colors[color_index++]);if (color_index >= colors.Length)
    2.  
      {
    3.  
      color_index = 0;
    4.  
      }
    5.  
       
    6.  
      browser.GetMainFrame().ExecuteJavaScriptAsync(script);

    什么时候可以开始执行 Javascript ?

    不幸的是加载DOM之前OnFrameLoadStart被调用,所以你需要使用如下之一:FrameLoadEnd / LoadingStateChanged / IRenderProcessMessageHandler.OnContextCreated。下面是几个例子

    不幸的是,在加载DOM之前调用 OnFrameLoadStart ,所以你需要使用下面的一个方法: FrameLoadEnd/LoadingStateChanged/IRenderProcessMessageHandler.OnContextCreated 。这里有几个例子

    1.  
      browser.RenderProcessMessageHandler = new RenderProcessMessageHandler();
    2.  
       
    3.  
      public class RenderProcessMessageHandler : IRenderProcessMessageHandler
    4.  
      {
    5.  
      // Wait for the underlying `Javascript Context` to be created, this is only called for the main frame.
    6.  
      // If the page has no javascript, no context will be created.
    7.  
      void IRenderProcessMessageHandler.OnContextCreated(IWebBrowser browserControl, IBrowser browser, IFrame frame)
    8.  
      {
    9.  
      const string script = "document.addEventListener('DOMContentLoaded', function(){ alert('DomLoaded'); });";
    10.  
       
    11.  
      frame.ExecuteJavaScriptAsync(script);
    12.  
      }
    13.  
      }
    14.  
       
    15.  
      //Wait for the page to finish loading (all resources will have been loaded, rendering is likely still happening)
    16.  
      browser.LoadingStateChanged += (sender, args) =>
    17.  
      {
    18.  
      //Wait for the Page to finish loading
    19.  
      if (args.IsLoading == false)
    20.  
      {
    21.  
      browser.ExecuteJavaScriptAsync("alert('All Resources Have Loaded');");
    22.  
      }
    23.  
      }
    24.  
       
    25.  
      //Wait for the MainFrame to finish loading
    26.  
      browser.FrameLoadEnd += (sender, args) =>
    27.  
      {
    28.  
      //Wait for the MainFrame to finish loading
    29.  
      if(args.Frame.IsMain)
    30.  
      {
    31.  
      args.Frame.ExecuteJavaScriptAsync("alert('MainFrame finished loading');");
    32.  
      }
    33.  
      };

    注意:脚本是在 Frame 级别执行,永远页面至少有一个Frame( MainFrame )。 IWebBrowser.ExecuteScriptAsync 扩展方法是为了向后兼容,可以将其用作在主框架上执行 js 的快捷方式。

    2. 如何获取 Javascript 方法返回的结果?

    如果需要评估返回值的代码,使用 Task<JavascriptResponse> EvaluateScriptAsync(string script, TimeSpan? timeout) 方法。 JavaScript代码是异步执行的,因此使用.NET Task 类返回一个响应,其中包含错误消息,结果和一个成功(bool)标志。

    1.  
      // Get Document Height
    2.  
      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);
    3.  
       
    4.  
      task.ContinueWith(t =>
    5.  
      {
    6.  
      if (!t.IsFaulted)
    7.  
      {
    8.  
      var response = t.Result;
    9.  
      EvaluateJavaScriptResult = response.Success ? (response.Result ?? "null") : response.Message;
    10.  
      }
    11.  
      }, TaskScheduler.FromCurrentSynchronizationContext());

    有关更详细的例子 Gist

    Notes

    • 脚本是在 Frame 级别执行,永远页面至少有一个Frame( MainFrame )
    • 只能返回一般的值(如int,bool,string等) - 不是您自己定义的复杂(用户定义)类型。这是因为没有(容易的)方式将随机的JavaScript对象暴露给.NET World,至少不是今天。但是,一种可能的技术是,将要返回到.NET代码的Javascript对象转换为JSON对象,使用 JSON.toStringify() 方法转化为JSON字符串,并将该字符串返回到您的.NET代码。然后,您可以将该字符串解码为一个类似JSON.net的.NET对象。有关更多信息,请参阅此MSDN链接。 (https://msdn.microsoft.com/library/cc836459(v=vs.94).aspx)

    3. 如何暴露.NET类,提供给Javascript?

    参考 般使用指南 - 如何公开.Net类

    4. 为什么我得到一个错误有关“无法加载文件或程序集 CefSharp.Core.dll”或它的一个依赖。指定的模块找不到。“当试图运行基于我CefSharp的应用程序?它编译成功,但不运行?它运行我的开发机器上,虽然抛出一个异常,当我把它复制到另一台计算机?

    这是一个常见的错误,通常是以下之一

    1. VC++ 2012/2013 可重新分发包*是为了在非开发者机器上运行CefSharp所必需的。有关详细信息,请参阅下面的FAQ#6。 您可以将所需的dll作为应用程序的一部分。
    2. 执行文件夹中不存在所有依赖关系。 CefSharp 包括 非托管 的dll和资源,这些文件通过安装 Nuget 包时包含在项目中的两个 .props 文件复制到执行文件夹。 请参阅下面所需的文件列表,确保所需的文件存在。
    3. 你通过安装程序打包应用程序进行发布,并且不会在目标计算机上运行。 默认情况下,安装程序不包括 非托管 资源,您需要手动添加它们。 对于 ClickOnce ,请参阅#1314其他用户提出的一些指针和解决方案。

    可以在这里找到所需文件的列表:Output files description (Redistribution)

    注: 如果在 XAML 中初始化 WPF 控件时遇到 FileNotFoundException ,这也适用。

    注2:如果从源代码编译(不推荐使用 Nuget 包),并注意到您不能再以debug模式构建,但是release构建工作正常,您可能需要修复Visual Studio版本。 这种情况发生在少数情况下,您将获得如上所示,丢失的非托管.dll文件相同的提示信息。

    5. 为什么当我将 ChromiumWebBrowser 添加到我的应用程序时,Visual Studio WPF设计器不起作用?

    注 版本 57.0.0 增加了最小的设计器支持,有关详细信息,请参见 https://github.com/cefsharp/CefSharp/pull/1989。

    旧版本不支持 WPF 设计器,这是不幸的,CefSharp是用C++代码编写的,后者又引用了CEF DLLs 导致的结果。这种情况下,Visual Studio 设计器不能够很好的支持。在论坛的主题将进一步解释,并提供可能的解决方法。 我认为(不幸的是)最简单的解决方法是接受一个事实,即支持并不容易,但是还有其他方法,如果你真的觉得你需要旧版本。

    6. 如何在目标应用程序中包含Visual Studio C ++ 2012/2013 再发布

    CefSharp 需要 VC ++运行时 。你必须安装/包括这与你的应用程序的几个选项:

    • 你可以在你希望运行 CefSharp 基于应用程序的每台计算机上安装 VC++ 。一旦安装更新就可以通过 Windows Update 进行管理。
    • 您可以设置在 Visual Studio C++ 再分发作为安装程序的先决条件(即的ClickOnce或WiX的工具集)
    • 通过复制到您的项目在此文件夹(只有当你安装了Visual Studio中的匹配版本存在)的内容:
    1.  
      #对于VC ++ 2012(86)
    2.  
      C:Program Files (x86)Microsoft Visual Studio 11.0VCredistx86Microsoft.VC110.CRT
    3.  
      #对于VC ++ 2012(64)
    4.  
      C:Program Files (x86)Microsoft Visual Studio 11.0VCredistx64Microsoft.VC110.CRT
    5.  
      #对于VC ++ 2013(86)
    6.  
      C:Program Files (x86)Microsoft Visual Studio 12.0VCredistx86Microsoft.VC120.CRT
    7.  
      #对于VC ++ 2013(64)
    8.  
      C:Program Files (x86)Microsoft Visual Studio 12.0VCredistx64Microsoft.VC120.CRT

    随着第三方法,你将不再需要为前提的 Visual C++ 2012/2013 运行时文件 安装到客户端。就目前的计划是留在VC2013官方CefSharp二进制版本。可行时,我们可能会切换到VC2015。如果你从源代码构建自己的你部署的过程中必须与您构建环境。对于官方的 Nuget 版本的详细信息请参见发布分支表

    欲了解更多信息,请参阅重新分发 Visual C++ 文件。要下载,请访问Visual Studio C++ 2012/2013 再发行

    一个新的选项是 JetBrains 在 Nuget.org 上有一个Microsoft.VC120.CRT.JetBrains ,似乎包含相关文件,您仍然需要连接一些后期构建任务将其复制到您的bin文件夹。

    注意 当从源代码构建时,确保在部署到没有安装 Visual Studio 的机器时以 Release 模式进行编译。 Visual C++ 使用一套不同的调试和发布版本的运行时库。 Debug 运行时库仅安装有 Visual Studio 中。如果你使用他们已经建在释放模式官方的 NuGet软件包 ,您可以随后建立在调试模式下您的应用程序,因为只有在 Visual C++ 项目需要在 Release 模式下进行编译。

    7. 如何重写 Javascript 的 window.alert 事件和相似的事件?

    ChromiumWebBrowser 控件提供了一个名为 JsDialogHandler 的属性。 该属性可以设置为一个类,可以用来覆盖这些对话框的行为。

    8. CefSharp3二进制程序在哪里?

    CefSharp3被发布为 Nuget 包。 请参阅https://github.com/cefsharp/CefSharp/blob/master/README.md#nuget-packages 以获取最新的稳定版本和预发行版本。

    对于使用NuGet软件包的一个非常简单的示例项目,请参阅CefSharp.MinimalExample 存储库。 克隆它/下载源码,如果你想要一个真正的小而简单的例子,如何使用CefSharp3。

    请注意: 平台目标

    使用这些包时,必须 选择 x86 或 x64 。 如果您选择 AnyCPU ,NuGet magic将无法正常工作。_请参阅steps to configure your solution here

    9. Windows XP/2003支持?

    我们不再支持 Windows XP/2003 。官方的 Nuget 软件包没有在 Windows XP/2003 上进行测试。 您可能会喜欢使用目标为 VC++ 2013 的较新版本( VC++ 2012 packages 有一个已知问题)。(记住 CefSharp.Example.* 项目是使用 .Net 4.5 编译的,所以如果你想使用提供的例子,你必须重新定位它们并相应地更新代码)。

    请不要创建与 Windows XP 相关的 新的 问题。 以下 https://github.com/cefsharp/CefSharp/wiki/Windows-XP-No-Longer-Supported Wiki 页面可能很有用,可以由任何具有 GitHub 帐户的人进行编辑,因此请随时提供,您认为可能证明有用的任何信息。

    10. 当我重新发布使用CefSharp的应用程序时,需要包括什么文件?

    请参阅: Output files description (Redistribution)

    11. 构建过程不能复制CEF文件

    有时,编译过程不能复制CEF文件,并且会在最终失败之前重试多次。 即使应用程序关闭,CefSharp.BrowserSubprocess.exe 仍然运行时也会发生这种情况。 解决方案,使用任务管理器,手动杀死 CefSharp.BrowserSubprocess.exe 。

    12. 为什么 IndexedDB 返回 QuotaExceededError?

    使用IndexedDB时,必须将CefSettings CachePath设置为当前用户具有写入权限的目录。 在大多数情况下,您可以使用这样的代码创建缓存目录,并在Initialize() 期间将设置传递给Cef:

    1.  
      // On Win7 this will create a directory in AppData.
    2.  
      var cache = System.IO.Path.Combine(Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), System.IO.Path.Combine("MyApplication","cache"));
    3.  
      if (!System.IO.Directory.Exists (cache))
    4.  
      System.IO.Directory.CreateDirectory (cache);
    5.  
       
    6.  
      // Set the CachePath during initialization.
    7.  
      var settings = new CefSettings(){CachePath = cache};
    8.  
      Cef.Initialize (settings);

    13. 在C#中如何处理Javascript事件?

    1.  
      public class BoundObject
    2.  
      {
    3.  
      public void OnFrameLoadEnd (object sender, FrameLoadEndEventArgs e)
    4.  
      {
    5.  
      if(e.Frame.IsMain)
    6.  
      {
    7.  
      browser.ExecuteScriptAsync(@"
    8.  
      document.body.onmouseup = function()
    9.  
      {
    10.  
      bound.onSelected(window.getSelection().toString());
    11.  
      }
    12.  
      ");
    13.  
      }
    14.  
      }
    15.  
       
    16.  
      public void OnSelected(string selected)
    17.  
      {
    18.  
      MessageBox.Show("The user selected some text [" + selected + "]");
    19.  
      }
    20.  
      }
    21.  
       
    22.  
      // ...
    23.  
       
    24.  
      // After your ChromiumWebBrowser has been instantiated (for WPF directly after `InitializeComponent();` in the control constructor).
    25.  
      var obj = new BoundObject();
    26.  
      browser.RegisterJsObject("bound", obj);
    27.  
      browser.FrameLoadEnd += obj.OnFrameLoadEnd ;

    请注意:

    • 在创建 ChromiumWebBrowser 实例之后,应该直接调用 RegisterJsObject
    • "bound" 将作为可在网页上运行的任何JS脚本访问的顶级对象创建的对象的名称。 您可以使用任何您喜欢的,但确保它不与现有的JS对象冲突,并且名称与C#和JS匹配。
    • 此示例使用 FrameLoadEnd 事件即时将JS代码注入到网页中。 如果您控制了网页,可以将JS代码添加到网页中。
    • 我们使用单个字符串参数调用 OnSelected C#方法。 您可以使用任何数量的参数,也可以不使用任何参数,但都必须是原始类型。
    • 确保将复杂的JS对象转换为字符串,或将其转换为JSON。
    • 由于CefSharp将通过其名称搜索 OnSelected 方法,请确保您的混淆器不会将该方法重命名为别的东西,否则将不会被执行。

    14. 如何实现 WinForms 拖放?

    一个可能的解决方案概述 https://github.com/cefsharp/CefSharp/issues/1593#issuecomment-304451518

    10、参考网址

    http://www.cnblogs.com/TianFang/p/4658151.html

    11、其他

    萌橙 你瞅啥?
  • 相关阅读:
    css3 flex
    多行文本溢出 显示... 判断是否多行文本溢出
    事件多次执行
    WinForm布局
    winform 公共控件
    WinForm窗体菜单和工具栏
    2017-4-24WinForm 基础
    2017-4-20实体类,数据访问类.字符串攻击.防攻击
    ADO.net增删改查
    类库,通用变量,is/as运算符,委托。
  • 原文地址:https://www.cnblogs.com/daimaxuejia/p/11698796.html
Copyright © 2020-2023  润新知