原文:使用CefSharp在.NET中嵌入Google kernel

  使用CefSharp可以在.NET轻松的嵌入Html,不用担心WPF与Winform 控件与它的兼容性问题,CefSharp大部分的代码是C#,它可以在VB或者其他.NET平台语言中来进行使用。

  近几天来,公司项目中需要使用WebBrowser,其中考虑了几个控件,如1.Winform中的WebBrowser    2.WPF中的WebBrowser    3.WebKit.Net     4.CefSharp

  Winform的WebBrowser放到项目中进行了实验和处理,发现致命问题:AllowsTransparency = true 和 Webbrowser 等内置窗体显示冲突,导致不发选择,还有就是GC回收不及时,一下子就飙到了100MB+.

  后来考虑WPF的webbrowser 它实际上还是封装了Winform,有个严重的问题就是它一直置顶到最顶层,so,无法选择。

  再后来考虑WebKit.Net ,但发现已经N多年没有更新,所以不在考虑...

  最后跌跌撞撞跑到CefSharp,发现非常的坑啊!!竟然不支持AnyCPU,关键是我的项目中有的功能是必须AnyCpu启动的啊!还好,官方在去年已经公布了支持AnyCpu的方法。

  首先Nuget引用cefsharp.WPF,它会自己引用Common,其他不用管。我们还需要再App.xaml.cs中添加代码来支持AnyCpu。

  1. public partial class App : Application
  2. {
  3. public App()
  4. {
  5. //Add Custom assembly resolver
  6. AppDomain.CurrentDomain.AssemblyResolve += Resolver;
  7.  
  8. //Any CefSharp references have to be in another method with NonInlining
  9. // attribute so the assembly rolver has time to do it's thing.
  10. InitializeCefSharp();
  11. }
  12.  
  13. [MethodImpl(MethodImplOptions.NoInlining)]
  14. private static void InitializeCefSharp()
  15. {
  16. var settings = new CefSettings();
  17.  
  18. // Set BrowserSubProcessPath based on app bitness at runtime
  19. settings.BrowserSubprocessPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
  20. Environment.Is64BitProcess ? "x64" : "x86",
  21. "CefSharp.BrowserSubprocess.exe");
  22.  
  23. // Make sure you set performDependencyCheck false
  24. Cef.Initialize(settings, performDependencyCheck: false, browserProcessHandler: null);
  25. }
  26.  
  27. // Will attempt to load missing assembly from either x86 or x64 subdir
  28. // Required by CefSharp to load the unmanaged dependencies when running using AnyCPU
  29. private static Assembly Resolver(object sender, ResolveEventArgs args)
  30. {
  31. if (args.Name.StartsWith("CefSharp"))
  32. {
  33. string assemblyName = args.Name.Split(new[] { ',' }, )[] + ".dll";
  34. string archSpecificPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
  35. Environment.Is64BitProcess ? "x64" : "x86",
  36. assemblyName);
  37.  
  38. return File.Exists(archSpecificPath)
  39. ? Assembly.LoadFile(archSpecificPath)
  40. : null;
  41. }
  42.  
  43. return null;
  44. }
  45. private void Application_Startup(object sender, StartupEventArgs e)
  46. {
  47. }
  48. }

  还没完,之后你得在你项目的 *.csproj 中添加一行配置,它是在你的第一个PropertyGroup中添加的。

最后一步,在App.config中配置x86,当然不是说不支持CPU,刚刚App.xaml.cs中我们已经修改了啊。

  1. <configuration>
  2. <runtime>
  3. <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  4. <probing privatePath="x86"/>
  5. </assemblyBinding>
  6. </runtime>
    </...>

就现在我们在页面中添加一个CefSharpBrowser在grid中,您需要在容器空间中添加name 标记。

  1. public static ChromiumWebBrowser cefSha { get; set; }
  2. public Visualization()
  3. {
  4. InitializeComponent();
  5. }
  6. private void Page_Loaded(object sender, RoutedEventArgs e)
  7. {
  8. cefSha = new ChromiumWebBrowser(Environment.CurrentDirectory + "/../../Pages/STORE/VisualizationHtml/StoreData.html");
  9.  
  10. // 页面加载完毕后打开开发者工具
  11. cefSha.KeyboardHandler = new CEFKeyBoardHander();
  12. CefSharpSettings.LegacyJavascriptBindingEnabled = true;
  13. NewMutliPage();
  14. this.grid.Children.Add(cefSha);//初始化
  15. }

前后端交互都是在NewMutliPage中搭起的桥梁,该代码是新版本的配置方式,大概是18年底,前后端的钩子可以通过bound来偷取。

  1. public void NewMutliPage()
  2. {
  3. cefSha.JavascriptObjectRepository.ResolveObject += (s, eve) =>
  4. {
  5. var repo = eve.ObjectRepository;
  6. if (eve.ObjectName == "bound")
  7. {
  8. repo.Register("bound", new JsEvent(), isAsync: true,
  9. options: new BindingOptions()
  10. {
  11. CamelCaseJavascriptNames = false
  12. });
  13. }
  14. };
  15. }

老版本你可以这么配置前后端交互的桥梁。

  1. public void OldSinglePage()
  2. {
  3. // 新版本默认为 false
  4. CefSharpSettings.LegacyJavascriptBindingEnabled = true;
  5. // 把 TestClass 注入到单个页面,名称为 test
  6. _chromiumWebBrowser.RegisterJsObject("testold", new TestClass());
  7. }
  1.  LegacyJavascriptBindingEnabled 该属性就是让WebBrowserWPF支持js交互,否则不可以建立jsObject 这个对象。

     RegisterJsObject 中我们是绑定的类,该类中是我们后台向WebBrowser的所有数据方法。
  1. public class JsEvent
  2. {
  3. /// <summary>
  4. /// 根据货架列代码区查相关信息
  5. /// </summary>
  6. /// <param name="Sline_code"></param>
  7. public void GetobjBySline_Code(string Sline_code)
  8. {
  9. Visualization.cefSha.ExecuteScriptAsync($@"getgoods({
  10. Newtonsoft.Json.JsonConvert.SerializeObject(VisualizationDAL.GetList(Sline_code))});");
  11. }
  12. /// <summary>
  13. /// 获取货架信息
  14. /// </summary>
  15. /// <param name="Sline_code"></param>
  16. public void GetShelveDetail(string Sline_code)
  17. {
  18. //1.找到那列的所有货架
  19. ObservableCollection<STORE_SHELVE> shelveList = XDAL.STORE_SHELVE_DAL.GetListByLineName(Sline_code);
  20. //2.找到关于该列下所有的商品信息
  21. ObservableCollection<STORe_DetailVm> detailList = new ObservableCollection<STORe_DetailVm>();
  22. foreach (var item in shelveList)
  23. {
  24. XDAL.STORE_goods_Detail.GetGoodsDetail(item.Shelve_code).ToList().ForEach(obj =>
  25. {
  26. detailList.Add(obj);
  27. });
  28. }
  29. #region
  30. List<VisualShelveVm> VisualList = new List<VisualShelveVm>();
  31. for (int i = ; i < shelveList.Count; i++)
  32. {
  33. //循环最大粒子,在这个最大粒子当中来组织Json
  34. for (int g = ; g < ; g++)
  35. {
  36. for (int l = ; l < ; l++)
  37. {
  38. var store_detail = detailList.FirstOrDefault(a => a.grid == g.ToString()
  39. && a.Shelve_code == shelveList[i].Shelve_code
  40. && a.layer == l.ToString());
  41. //如果未出库的里没有这个 那就可以添加
  42. if (store_detail != null)
  43. {
  44. VisualList.Add(new VisualShelveVm()
  45. {
  46. shelve_grid = g.ToString(),
  47. shelve_layer = l.ToString(),
  48. shelve_code = shelveList[i].Shelve_code,
  49. shelve_name = shelveList[i].Shelve_name,
  50. isHas = true,
  51. goods_code = store_detail.Goods_code,
  52. goods_name = store_detail.Goods_name
  53. });
  54. }
  55. else
  56. {
  57. VisualList.Add(new VisualShelveVm()
  58. {
  59. isHas = false,
  60. shelve_grid = g.ToString(),
  61. shelve_layer = l.ToString(),
  62. });
  63. }
  64. }
  65. }
  66. }
  67. #endregion
  68. Visualization.cefSha.ExecuteScriptAsync($@"GetShelve({Newtonsoft.Json.JsonConvert.SerializeObject(VisualList)});");
  69. }

  需要注意的是该代码块的最后一行,这是我们用前端方法的方式,Visualization是我们刚才的页面,我们直接调用静态CefSha然后执行它的异步方法,其中是直接执行的Js,它和Wpf自带的WebBrowser还不一样,微软的WebBrowser是高度封装的,而cefsha是高度开源的,这一块不得不赞了。

  前台如何请求后台呢?首先在页面加载的时候配置下bound对象。

  1. <script>
  2. window.onload = function () {
  3. loadScrollWidth();
  4. // 新式注入
  5. CefSharp.BindObjectAsync("bound");
  6. }
  7. </script>

随后我们就可以通过bound这个对象来请求后台了

  1. bound.GetobjBySline_Code(Sline_Code);

就以我来说,千万不要拿Jquery和Vue一起用,真的是太糟心了..

  1. <body>
  2. <div class="container" id="app" style="max-width: 1600px;">
  3. <div class="row">
  4. <div class="col-lg-3">
  5. <div class="card">
  6. <h3 class="card-img-top headtext">清单</h3>
  7. <div class="card-body">
  8. <table class="table table-striped">
  9. <thead>
  10. <tr>
  11. <th scope="col">分类名称</th>
  12. <th scope="col">数量</th>
  13. </tr>
  14. </thead>
  15. <tbody>
  16. <tr v-for="(item,index) in goods_item">
  17. <th scope="row">{{item.goods_Name}}</th>
  18. <td>{{item.num}}</td>
  19. </tr>
  20. </tbody>
  21. </table>
  22. </div>
  23. </div>
  24. </div>
  25. <div class="col-lg-9" style="overflow: scroll;">
  26. <div class="row line_div">
  27. <div class="row" style="font-size: 20px;background-color: #CCC;width: 100%;">
  28. <ul class="nav nav-pills nav-fill" id="nav_list">
  29. <li class="nav-item" v-for="(item,index) in line_item">
  30. <!-- 如果 index -->
  31. <a class="nav-link active" key="item.Sline_code" @click="toggle(index,item)" v-if="index==0">{{item.Sline_name}}</a>
  32. <!-- index n -->
  33. <a class="nav-link" key="item.Sline_code" @click="toggle(index,item)" v-if="index!=0">{{item.Sline_name}}</a>
  34. </li>
  35. </ul>
  36. </div>
  37. <div class="row" style="margin-left: 0;" id="VisualBody">
  38. <div class="colums" v-for="item in reversedMessage">
  39. <div class="row">
  40. <img src="tx_3.png">
  41. <div class="table_div">
  42. <table class="custormTable" style="margin-top: 40px;" :id="item.code">
  43. </table>
  44. </div>
  45. </div>
  46. <div class="row"
  47. style="background-image: url('tx_2.png');width: 556px;height:464px;background-repeat: repeat-y;">
  48. </div>
  49. <div class="row">
  50. <img src="tx_1.png">
  51. <div class="hj_center">
  52. <h3>{{item.name}}</h3>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. </div>
  60. </div>
  61. </body>
  62. <script>
  63. window.onload = function () {
  64. loadScrollWidth();
  65. // 新式注入
  66. CefSharp.BindObjectAsync("bound");
  67. }
  68. </script>
  69. <script>
  70. function loadScrollWidth(num) {
  71. var tags = document.getElementsByClassName('line_div')[];
  72. tags.style.width = num * + 'px';
  73. }
  74. function changedom(listdata,shelvedata) {
  75. var num = ;
  76. $(".custormTable").html("");
  77. shelvedata.shift();
  78.  
  79. for (var i = ; i < shelvedata.length; i++) {
  80. var shelve_code = shelvedata[i].shelve_code;
  81. //不管如何都是循环4X4
  82. for (var y = ; y < ; y++) {
  83. var goodshtml = '<tbody><tr class="store_goodsName">';
  84. var numhtml = '<tr class="store_goodsId">'
  85. numhtml += "<td>" + num + "</td>";
  86. numhtml += "<td>" + (num + ) + "</td>";
  87. numhtml += "<td>" + (num + ) + "</td>";
  88. numhtml += "<td>" + (num + ) + "</td>";
  89. numhtml = numhtml + '</tr>';
  90. for (var g = ; g < ; g++) {
  91. var obj = listdata.find(item => item.shelve_layer == y && item.shelve_grid == g && item.shelve_code == shelve_code);
  92. if (obj != null) {
  93. if (obj.isHas == true) {
  94. goodshtml = goodshtml + "<td>" + obj.goods_name + "</td>";
  95. }
  96. } else {
  97. goodshtml = goodshtml + "<td></td>";
  98. }
  99. }
  100. goodshtml = goodshtml + '</tr>' + numhtml + '</tbody>';
  101. var my_element = $("#" + shelve_code);
  102. $("#" + shelve_code).append(goodshtml);
  103. num = num + ;
  104. }
  105. }
  106. }
  107.  
  108. </script>
  109. </html>
  110. <script>
  111. var app = new Vue({
  112. el: "#app",
  113. data: {
  114. m: "hello",
  115. line_item: [],//列
  116. goods_item: [],//商品列表+num
  117. shelve_list: [],//货架列表
  118. Listdata: [],//商品列表
  119.  
  120. },mounted() {
  121. //全局钩子引用
  122. window.getalert = this.getalert;
  123. window.getgoods = this.getgoods;
  124. window.GetShelve = this.GetShelve;
  125. window.DBTwo = this.DBTwo;
  126. },methods: {
  127. getalert: function (list) {
  128. this.line_item = typeof list == 'string' ? JSON.parse(list) : list;
  129. },toggle:function(index,item){
  130. $(".nav-item a").each(function () {
  131. $(this).removeClass("active");
  132. });
  133. $(".nav-item a").eq(index).addClass('active');
  134. //item 对象 Sline_Code 【字段】
  135. var Sline_Code = item.Sline_code;
  136. //调用完之后C#会找我们的一个方法然后将参数带过来
  137. bound.GetShelveDetail(Sline_Code);
  138. //请求后台,让后台直接调用一个方法去加载列表。
  139. bound.GetobjBySline_Code(Sline_Code);
  140. this.Wecas(index, item);
  141. },Wecas: function (index, item) {
  142. $(".nav-item a").each(function () {
  143. $(this).removeClass("active");
  144. });
  145. $(".nav-item a").eq(index).addClass('active');
  146. //item 对象 Sline_Code 【字段】
  147. var Sline_Code = item.Sline_code;
  148. //调用完之后C#会找我们的一个方法然后将参数带过来
  149. bound.GetShelveDetail(Sline_Code);
  150. //请求后台,让后台直接调用一个方法去加载列表。
  151. bound.GetobjBySline_Code(Sline_Code);
  152. },getgoods: function (goods_list) {
  153. //该方法是返回货架有的物品
  154. this.goods_item = typeof goods_list == 'string' ? JSON.parse(goods_list) : goods_list;
  155. }, GetShelve: function (list) {
  156. this.Listdata = list;
  157. let obj = {};
  158. list = list.reduce((cur, next) => {
  159. obj[next.shelve_code] ? "" : obj[next.shelve_code] = true && cur.push(next);
  160. return cur;
  161. }, []);
  162. this.shelve_list = typeof list == 'string' ? JSON.parse(list) : list;
  163. changedom(this.Listdata, this.shelve_list);
  164. }
  165. }, computed: {
  166. //所有的货架列出来
  167. reversedMessage: function () {
  168. var array = [];
  169. for(var i=;i<this.shelve_list.length;i++){
  170. //判断是否name是不是有
  171. if (this.shelve_list[i].shelve_name != null) {
  172. var obj = {
  173. name: this.shelve_list[i].shelve_name,
  174. code : this.shelve_list[i].shelve_code
  175. }
  176. array.push(obj);
  177. }
  178. }
  179. if (array.length < ) {
  180. loadScrollWidth();
  181.  
  182. } else {
  183. loadScrollWidth(array.length);
  184. }
  185. return array;
  186. }
  187. }
  188. });
  189. </script>

  前后端交互最好是前端请求后端,然后让后端执行前端的Js带上参数。

需要注意的cefsharp初次调用js的是 cefSha.ExecuteScriptAsyncWhenPageLoaded($"getalert({str});");  我也是醉

  还有就是在开发中一定想要F12 看看代码运行状况如何或者要调试。

  1. class CEFKeyBoardHander : IKeyboardHandler
  2. {
  3. public bool OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
  4. {
  5. if (type == KeyType.KeyUp && Enum.IsDefined(typeof(Keys), windowsKeyCode))
  6. {
  7. var key = (Keys)windowsKeyCode;
  8. switch (key)
  9. {
  10. case Keys.F12:
  11. browser.ShowDevTools();
  12. break;
  13. }
  14. }
  15. return false;
  16. }
  17.  
  18. public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
  19. {
  20. return false;
  21. }
  22. }

ok就这样·~效果图

2019/8/27 更新 cefsharp调用后台C#代码中 有操作UI的 则需要

  1. public void Show(string Code)
  2. {
  3. App.Current.Dispatcher.Invoke((Action)(() =>
  4. {
  5. 。。。。。。。。。
  6. }
  7. }

使用CefSharp在.NET中嵌入Google kernel的更多相关文章

  1. 在VC/MFC中嵌入Google地图——图文并茂

    近期须要实验室须要将在无人机地面站中嵌入地图,在网上找了非常多资料,最终有些眉目了, 首先.做这个须要用到的知识有.MFC控件.MFC类库.JavaScript脚本语言.Google API.Goog ...

  2. 使用CefSharp在.NET中嵌入Chromium

    使用CefSharp可以在.NET轻松的嵌入Html,不用担心WPF与Winform 控件与它的兼容性问题,CefSharp大部分的代码是C#,它可以在VB或者其他.NET平台语言中来进行使用. 近几 ...

  3. 网页中嵌入google地图

    一丶前言 大致需求:美国地图中标记分布的仓库图钉(鼠标经过显示地址详情),通过输入寄收件地邮编来在地图上定位位置添加图钉,将寄件地,选择的仓库,收件地图钉折线相连接,表示大致路线. 一丶google开 ...

  4. 转-使用 CefSharp 在 C# App 中嵌入 Chrome 浏览器

    使用 CefSharp 在 C# App 中嵌入 Chrome 浏览器 2016-09-23    分类:.NET开发.编程开发.首页精华0人评论 分享到:更多3 本文由码农网 – 小峰原创翻译,转载 ...

  5. 使用CefSharp在.Net程序中嵌入Chrome浏览器(一)——简介

    有的时候,我们需要在程序中嵌入Web浏览器,其实.Net Framework中本身就提供了WebBrowser控件,本身这个是最简单易用的方案,但不知道是什么原因,这个控件在浏览网页的时候有些莫名的卡 ...

  6. 使用CefSharp在.Net程序中嵌入Chrome浏览器(二)——参数设置

    在实现了.Net程序中嵌入Chrome浏览器后,下一步的个性化操作就是加入一些设置了,在前面的文章中,我们可以看到在使用Chrome控件前,有如下一个操作: var setting = new Cef ...

  7. 在Flex (Flash)中嵌入HTML 代码或页面—Flex IFrame

    在flex组件中嵌入html代码,可以利用flex iframe.这个在很多时候会用到的,有时候flex必须得这样做,如果你不这样做还真不行-- flex而且可以和html进行JavaScript交互 ...

  8. [转]在 Eclipse 中嵌入 NASA World Wind Java SDK

    使用此开源 SDK 开发 GIS 应用程序 NASA 开发的开源 World Wind Java (WWJ) SDK 为地理信息系统(Geographic Information Systems,GI ...

  9. 在Flex (Flash)中嵌入HTML 代码或页面—Flex IFrame

    在flex组件中嵌入html代码,可以利用flex iframe.这个在很多时候会用到的,有时候flex必须得这样做,如果你不这样做还真不行…… flex而且可以和html进行JavaScript交互 ...

随机推荐

  1. 微信小程序_(map)简单的小地图

    map地图效果 官方文档:传送门 Page({ data: { markers: [{ iconPath: "/resources/others.png", id: 0, lati ...

  2. LeetCode117----填充同一层兄弟节点

    给定一个二叉树 struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *next; } 填充它的每个 ...

  3. Python中Counter统计数据输出具体办法

    from collections import Counter # 列表 l_one = [1709020621, 1709020621, 1770603107, 1770603105, 177060 ...

  4. Scala学习(二)——高级特性

    apply() 方法 apply方法是Scala提供的一个语法糖 类名+括号,调用对象的apply方法 对象名+括号,调用类的apply方法 对apply方法的简单测试:(其中,带 new -- cl ...

  5. EventChannel 原生向Flutter传递数据

    目的:原生页面主动向Flutter页面传递信息 1 flutter步骤 定义EventChannel static const EventChannel eventChannel = EventCha ...

  6. 【转】JS正则验证邮手机、箱等格式

    function test() { var temp = document.getElementById("text1"); //对电子邮件的验证 var myreg = /^([ ...

  7. 第四章 SpringCloud之Eureka-Client实现服务(Jpa,H2)

    1.pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="h ...

  8. web开发(三) 会话机制,Cookie和Session详解

    在网上看见一篇不错的文章,写的详细. 以下内容引用那篇博文.转载于<http://www.cnblogs.com/whgk/p/6422391.html>,在此仅供学习参考之用. 一.会话 ...

  9. 使用ssh-agent管理私钥

    使用ssh-agent的好处: 如果有多台远程服务器与多个私钥文件,ssh-gent将会尝试使用不同的私钥文件建立连接,直至成功 假如有 A.B.C 三台服务器,A是控制节点,A可以直接登录B,但是无 ...

  10. k8s、CI/CD、pipline介绍

    参照文档: https://blog.csdn.net/qq_35299863/article/details/84329798 https://github.com/xgh2016/k8s-CICD ...