在我的部落格《C#開發BIMFACE系列52 CS客戶端整合BIMFACE應用的技術方案》中介紹了多種整合BIMFACE到客戶端程式中的方案。最後推薦大家使用 CefSharp元件與WebView2元件。本篇文章介紹使用CefSharp元件如何整合BIMFACE到客戶端程式中。
CefSharp是一個圍繞Chromium Embedded Framework(CEF)的輕量級.NET包裝器。它是用C++/CLI編寫的。允許開發者在.NET應用程式中嵌入Chromium。可以在C#或VB或任何其他CLR語言中使用。CefSharp同時提供WPF和WinForms Web瀏覽器控制元件實現。
功能特點
- 免費、開源:https://github.com/cefsharp/CefSharp
- 完善的文件
- 支援JS、C#、WinForm窗體之間相互通訊與呼叫
- 相容性較好,支援H5、CSS5、WebGL等
- 支援獲取Cookies較全面
- 其他
步驟1 新建WinForm專案
新建一個WinForm窗體應用程式,目標框架選擇 .NET Framework 4.5.2,因為新版本的CefSahrp元件最低支援 .NET Framework 4.5.2。
步驟2 通過 NeGet 下載
開啟NeGet
(1)搜尋 CefSharp
(2)選擇 CefSharp.WinForms
(3)選擇最新版本
(4)點選【安裝】按鈕
點選【確定】開始安裝。
安裝完成後,專案中自動新增了CefSharp.dll、CefSharp.Core.dll、CefSharp.WinForms.dll 類庫引用。
工具箱中也增加了CefSharp控制元件
步驟3 編譯專案
編譯 BIMFace.SDK.CSharp.Sample.WinForm 專案,生成如下內容
與 CefSharp 相關的共計32個檔案,2個目錄,檔案大小總計216M。這個尺寸相對於業務系統本身來說已經非常大了,最後製作的安裝包尺寸也會很大。
其中 locales 目錄下是語言包,刪除 zh-CN.pak 之外的所有檔案,總檔案大小可以減少22M左右。
測試功能設計如下
功能說明
(1)WinForm中載入的網頁來自於 BIMFace.SDK\BIMFace.SDK.CSharp.Sample\Pages\BIMFaceDemo7_3.html,所以Web專案要首先執行。
(2)WinForm 窗體中輸入 BIMFACE FileId,點選【載入模型/圖紙】按鈕,呼叫CefSahrp元件,載入步驟(1)中的網頁。程式碼如下:
1 // 載入模型/圖紙 2 private void btnLaodBIMFaceFile_Click(object sender, EventArgs e) 3 { 4 string fileId = txtBIMFaceFileId.Text.Trim(); 5 if (string.IsNullOrEmpty(fileId)) 6 { 7 MessageBox.Show("請填寫 BIMFACE FileId。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); 8 return; 9 } 10 // 將 ChromiumWebBrowserBindObject 例項物件注入到 js 物件中。網頁中即可呼叫 ChromiumWebBrowserBindObject 類中定義的屬性、方法 11 var objToBind = new ChromiumWebBrowserBindObject(); 12 chromiumWebBrowser1.JavascriptObjectRepository.Register("_chromeBrowser", objToBind, true, BindingOptions.DefaultBinder); 13 14 string url = "https://localhost:44389/Pages/BIMFaceDemo7_3.html?fileId=" + fileId; 15 chromiumWebBrowser1.Load(url); 16 }
(3)網頁中點選【JS 呼叫 C# 方法】按鈕。程式碼如下:
在入口函式中,獲取注入的 ChromiumWebBrowser 物件,名稱為 _chromeBrowser。
按鈕對應的js方法
1 // js 呼叫 C# 方法 2 function callCharpMethod() { 3 // 特別提醒:C# 類中定義的方法名稱採用 Pascal 命名。網頁中呼叫的時候必須將方法名稱的第一個字母改為小寫。否則呼叫不成功。 4 _chromeBrowser.testCalcAdd(6,8) 5 .then(function (response) { 6 alert(response); 7 }); 8 }
特別提醒:C# 類中定義的方法名稱採用 Pascal 命名。網頁中呼叫的時候必須將方法名稱的第一個字母改為小寫。否則呼叫不成功。
呼叫的C#方法。定義一個單獨的類,用於在CefSahrp元件載入網頁之前,將其注入到網頁中
(4)WinForm窗體中點選【 C# 呼叫 JS 方法】按鈕。程式碼如下:
1 // C# 呼叫 JS 方法 2 private void btnCsharpCallJsMethod_Click(object sender, EventArgs e) 3 { 4 Task<JavascriptResponse> jsResponse = chromiumWebBrowser1.EvaluateScriptAsync("jsMethodForCSharpTestCalcSub", 25, 7); 5 6 if (jsResponse.Result != null && jsResponse.Result.Success == false) 7 { 8 MessageBox.Show("C#呼叫JS方法發生異常。" + jsResponse.Result.Message 9 , "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); 10 } 11 }
網頁中定義的 jsMethodForCSharpTestCalcSub() 方法如下:
1 // js 方法,供C#呼叫 2 function jsMethodForCSharpTestCalcSub(num1, num2) { 3 /*如果引數需要是複雜型別,則傳遞Json格式的字串,然後反序列化為物件即可使用*/ 4 5 alert('傳入的引數num1:' + num1 + ", num2:" + num2 + ' 減法運算 num1 - num2 = ' + (num1 - num2)); 6 }
特別說明:
(1)C#定義的方法供JS呼叫,C#方法的返回值型別、引數型別都只能是簡單資料型別,如:int、string、bool 等。
(2)JS定義的方法供C#呼叫,JS方法的返回值型別、引數型別都只能是簡單資料型別,如:int、string、bool 等。
一般來說複雜型別就是一個實體類。如果確實想使用複雜型別,建議的解決方案如下:
將複雜型別序列化為字串,呼叫方將其反序列化之後再使用。
關於C#與JS互相通訊,請參考CefSahrp官方文件:https://github.com/cefsharp/CefSharp/wiki/General-Usage#3-how-do-you-expose-a-net-class-to-javascript
1、程式分析
(1)啟動應用程式,CefSharp元件未載入Web網頁時,預設啟動了2個 CefSharp.BrowserSubProcess 子程式。原因是我當前使用的CefSharp是94.4.50版本,每當new CefSharp.WinForms.ChromiumWebBrowser() 一個時,會啟動2個子程式。
(2)CefSharp元件載入Web網頁後,又啟動了2個 CefSharp.BrowserSubProcess 子程式,共計4個子程式。原因是 當 chromiumWebBrowser1.Load(url) 時啟動2個子程式。不同版本的 CefSharp 元件,啟動的子程式數量不同。
2、執行日誌分析
GPUCache目錄內容如下。BIMFACE載入模型/圖紙時利用了本地電腦的GPU強大的計算功能,所以產生了快取內容。
debug.txt 內如如下,裡面記錄了網頁的執行過程
- 通過NeGet安裝SDK時,執行時環境會被自動下載到當前專案的bin\debug 或者 bin\Release目錄下。導致整個專案非常大,大約220M左右。
- 以獨立程式方式執行,消耗記憶體較多。
如下是我的一個WinForm程式中使用CefSharp元件的執行狀態,其中一個子程式消耗記憶體達到1.5G,太可怕了
- 當控制元件Dock屬性設定為 Fill,客戶端電腦的縮放與佈局不是100%時,窗體呈現黑邊(嚴重bug),並沒有完全填充父容器。
《BIMFace.SDK.CSharp》開源SDK。歡迎大家下載使用。