C#使用CefSharp內嵌網頁-並給出C#與JS的互動範例

C#使用CefSharp內嵌網頁-並給出C#與JS的互動範例

有在客戶端內嵌網頁的需求嗎?CefSharp可能是個不錯的選擇!

最後更新 2023/3/27 下午10:43
沙漠尽头的狼
預計閱讀 8 分鐘
分類
.NET
標籤
.NET C# CefSharp

大家好,我是沙漠盡頭的狼。

本文介紹C# WPF裡怎麼使用CefSharp嵌入一個網頁,並給出一個簡單範例演示C#和網頁(JS)的互動實作。

一、範例搭建步驟

先給出本文範例程式碼:WpfWithCefSharpDemo

1. 建立專案

建立一個WPF專案,例如命名為「WpfWithCefSharpDemo」,Winform專案類似。

2. 建立一個網頁

嵌入的網頁可以是在線的(即給出一個URL),也可以是一個離線的HTML網頁,本文為了示範,在工程裡直接建立網頁test.html,屬性設定建置動作內容複製到輸出目錄如果較新則複製

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>CefSharp測試</title>
    <script>
        // 測試在Web中呼叫C#的方法
        function callCSharpMethod() {
            window.cefSharpExample.testMethod("來自JS的呼叫");
        }

        // 測試C#呼叫JS的方法,只傳遞一個普通的字串
        function displayMessage(message) {
            alert(message);
        }

        // 接收C#傳遞過來的JSON物件,並以表格形式展示在頁面上
        function displayJson(json) {
            var obj = JSON.parse(json);
            var html = "<table border='1'>";
            for (var prop in obj) {
                html += "<tr>";
                html += "<td>" + prop + "</td>"
                html += "<td>" + obj[prop] + "</td>"
                html += "</tr>"
            }
            html += "</table>";
            document.getElementById("jsonTable").innerHTML = html;
        }
    
    </script>
</head>
<body>
<h1>CefSharp測試</h1>
<button onclick="callCSharpMethod()">呼叫C#方法</button>
<div id="jsonTable"></div>
</body>
</html>

上面的程式碼給了相關的註解,應該很明瞭:

  • JS方法callCSharpMethod:用於測試JS呼叫C#的方法,其中cefSharpExample為C#註冊的一個物件,testMethod是其一個方法,JS中方法名首字母是小寫(C#裡按規則是大小),首字母這裡有區別,要注意一下;
  • JS方法displayMessagedisplayJson:用於測試C#呼叫JS的方法,方法定義類似,前者入參是一個普通字串,後者入參是一個JSON字串。
  • div元素jsonTable用於展示C#傳來的JSon物件資料。

3. 新增CefSharp套件

安裝CefSharp程式套件,可以在Visual Studio的NuGet套件管理員中搜尋CefSharp.Wpf並安裝。

4. 新增CefSharp控制項

MainWindow.xaml中引入CefSharp.Wpf命名空間(取別名為wpf,這裡隨意),將它的chromium控制項加入到視窗中,順便加幾個測試按鈕等:

<Window x:Class="WpfWithCefSharpDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:wpf="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
        mc:Ignorable="d"
        Title="WPF載入CefSharp測試" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="35"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Text="下面顯示的是網頁內容"></TextBlock>
        <Border Grid.Row="1" BorderBrush="DarkOrange" BorderThickness="2">
            <wpf:ChromiumWebBrowser x:Name="Browser" Loaded="Browser_OnLoaded">
            </wpf:ChromiumWebBrowser>

        </Border>
        <Border Margin="3 5" Grid.Row="2" BorderBrush="Blue" BorderThickness="2" VerticalAlignment="Center">
            <StackPanel Orientation="Horizontal" Height="35">
                <TextBlock Text="右側按鈕是WPF按鈕" VerticalAlignment="Center" Margin="5 3"></TextBlock>
                <Button Content="呼叫JS方法" Click="CallJSFunc_Click" Height="30" Padding="10 2"></Button>
                <Button Content="C#傳遞Json物件到網頁" Click="SendJsonToWeb_Click" Height="30" Padding="10 2"></Button>
            </StackPanel>
        </Border>
    </Grid>
</Window>

5. 在C#中呼叫JS方法

MainWindow.xaml.cs裡,加入相關控制項的事件處理方法,即C#呼叫JS方法的相關程式碼:

using CefSharp;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Text;
using System.Windows;

namespace WpfWithCefSharpDemo
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // 允許以同步的方式註冊C#的物件到JS中
            Browser.JavaScriptObjectRepository.Settings.LegacyBindingEnabled = true;
            CefSharpSettings.WcfEnabled = true;

            // 註冊C#的物件到JS中的程式碼必須在Cef的Browser載入之前呼叫
            Browser.JavaScriptObjectRepository.Register("cefSharpExample", new CefSharpExample(), false,
                options: BindingOptions.DefaultBinder);
        }

        /// <summary>
        /// Cef瀏覽器控制項載入完成後,載入網頁內容,可以載入網頁的Url,也可以載入網頁內容
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Browser_OnLoaded(object sender, RoutedEventArgs e)
        {
            var htmlFile = $"{AppDomain.CurrentDomain.BaseDirectory}test.html";
            if (!File.Exists(htmlFile))
            {
                return;
            }

            var htmlContent = File.ReadAllText(htmlFile, Encoding.UTF8);
            Browser.LoadHtml(htmlContent);
        }

        /// <summary>
        /// C#裡呼叫JS的一般方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CallJSFunc_Click(object sender, RoutedEventArgs e)
        {
            var jsCode = $"displayMessage('C#裡的呼叫')";
            Browser.ExecuteScriptAsync(jsCode);
        }

        /// <summary>
        /// C#呼叫一個JS的方法,並傳遞一個JSON物件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SendJsonToWeb_Click(object sender, RoutedEventArgs e)
        {
            var jsonContent = new
            {
                Id = 1,
                Name = "沙漠盡頭的狼",
                Age = 25,
                WebSite="https://dotnet9.com"
            };
            var jsonStr = JsonConvert.SerializeObject(jsonContent);

            // 傳遞Json物件,即傳遞一個JSON字串,和前面的一個範例一樣
            var jsCode = $"displayJson('{jsonStr}')";
            Browser.ExecuteScriptAsync(jsCode);
        }
    }

    public class CefSharpExample
    {
        public void TestMethod(string message)
        {
            Application.Current.Dispatcher.Invoke(() => { MessageBox.Show("JS裡的呼叫"); });
        }
    }
}

CefSharpExample用於封裝JS呼叫的類別及方法定義,注意C#這裡TestMethod方法名首字母是大寫的,前面建立的HTML網頁呼叫的該方法名首字母小寫,再提醒一次,這裡的區別要注意。

6. 效果展示

JS呼叫C#的方法:黃色方框內顯示的網頁內容,點擊HTML按鈕呼叫C#方法測試。

C#呼叫JS的普通方法:藍色方框內顯示的WPF控制項,點擊WPF按鈕呼叫JS方法測試。

C#傳遞Json物件給JS的方法:藍色方框內,點擊WPF按鈕C#傳遞Json物件到網頁測試。

二、總結

請對著上面的範例完成一遍,如果做過WPF或Winform原生WebBrowser控制項的使用者,我們這裡做個WPF自帶WebBrowser控制項與CefSharp的優劣勢對比結束本文(來自ChatGPT回答的結果),歡迎留言討論:

WPF自帶的WebBrowser控制項優勢:

  1. WebBrowser控制項是WPF自帶的,不需要安裝任何其他的函式庫或元件。

  2. WebBrowser控制項是基於Internet Explorer核心,因此它在Windows作業系統中有天然的相容性和穩定性。

  3. WebBrowser控制項提供了許多與瀏覽器相關的事件,例如Navigating、Navigated、LoadCompleted等,我們可以透過這些事件對網頁載入和導航進行控制和反饋。

WPF自帶的WebBrowser控制項劣勢:

  1. WebBrowser控制項使用的是舊版本的IE核心,不支援現代HTML5、CSS3等標準,而且在效能上也不如CefSharp。

  2. WebBrowser控制項的API相對較少,難以實現一些進階功能,例如攔截網頁導航、自訂渲染等。

CefSharp優勢:

  1. CefSharp是基於Chromium專案建置的,支援最新的HTML5、CSS3等Web標準,並且效能表現更出色。

  2. CefSharp提供了一套豐富的API,我們可以透過它來實現多種進階功能,例如自訂網路請求、攔截網頁導航、修改HTML內容等。

  3. CefSharp使用的是多執行緒模型和硬體加速渲染,不會阻塞UI執行緒,同時具有更好的穩定性和安全性。

CefSharp劣勢:

  1. CefSharp需要安裝額外的函式庫或元件,增加了開發的複雜度。

  2. CefSharp在某些情況下可能會出現效能問題,例如在高密度螢幕上渲染時。

因此,在選擇Web瀏覽器控制項時,我們需要根據具體的需求來選擇。如果只是簡單地展示網頁內容,並不需要過多的高階功能,那麼WPF自帶的WebBrowser控制項足以滿足需要。但如果需要實現一些複雜的功能,例如自訂網路請求、攔截網頁導航等,那麼CefSharp可能會更加適合。總的來說,CefSharp相對於WPF自帶的WebBrowser控制項,具有更強大的功能和更高的效能表現,但使用也相對更加複雜一些。

參考:

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2023/4/25

CefSharp自定義緩存實現

善用CefSharp的快取功能,可以提升應用程式的效能與用戶體驗,減少網路流量與伺服器負載,並支援離線存取,是一項非常有用的特性。

繼續閱讀