如何使用 Web 前端技術開發桌面應用程式 WinForm + CefSharp + Chromium - 起手式

CEF 的全名是 Chromium Embedded Framework,是用於嵌入 Chromium 瀏覽器的簡單框架,用 C++/CLI 開發

CefSharp 是在 .NET 平台封裝了 CEF,可以使用 C# / VB 語言開發

Winform 桌面應用程式要做出酷炫的畫面門檻相當的高,反觀當前的網頁技術發展的相當蓬勃,酷炫的畫面相當的多,CefSharp 可以讓我們嵌入 Chromium,輕鬆的使用前端技術,UI 的開發團隊,只要完成一個設計就可以同時給桌面應用程式和網站使用。

前端語言怎麼跟 C# 溝通?JavaScript + Handler 直接整合 C#  或者 JavaScript + Web API OWIN,這兩種方式都可以

 

開發環境

  • VS 2019
  • .NET Framework 4.8
  • .NET Core 3.1
  • CefSharp 79.1.360

專案

開啟兩個 WinForm 專案,一個是 .NET Framework 4.8,一個是 .NET Core 3.1

安裝

安裝套件

Install-Package CefSharp.WinForms
Install-Package CefSharp.Common
Install-Package JQuery
Install-Package Bootstrap

 

安裝 Visual C++ Redistributable 

安裝正確的 Visual C++ Redistributable,CefSharp 79 需要 C++ Redistributable 2015,

https://www.microsoft.com/zh-tw/download/details.aspx?id=53840

 

建置平台

預設 CefSharp 支援 x86 | x64,所以要先設定一下 Platform

 

調用 CefSharp

載入 Url

Cef.Initialize:初始化

Cef.Shutdown:關閉

https://github.com/cefsharp/CefSharp/wiki/General-Usage#initialize-and-shutdown

[STAThread]
private static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
  
    var settings = new CefSettings();
    Cef.Initialize(settings, false, browserProcessHandler: null);
 
    Application.Run(new Form1());
 
    Cef.Shutdown();
}

 

調用瀏覽器 ChromiumWebBrowser

ChromiumWebBrowser 建構子,可以傳遞 Url 或是 Html

public partial class Form1 : Form
{
    public ChromiumWebBrowser _browser;
 
    public Form1()
    {
        this.InitializeComponent();
        this.FormClosed += this.Form1_FormClosed;
 
        this._browser = new ChromiumWebBrowser("www.google.com")
        {
            Dock = DockStyle.Fill
        };
        this.Controls.Add(this._browser);
    }
 
    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
        this._browser?.Dispose();
    }
}

 

運行結果

 

載入自訂 html

安裝 JQuery、Bootstrap 之後,會得到 Connect、Scripts 資料夾

在 Views 資料夾新增 Index.html

<!DOCTYPE html>
 
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>hello world</title>
    <link href="../Content/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<h1 id="h1"></h1>
</body>
</html>
<script src="../Scripts/bootstrap.min.js"></script>
<script src="../Scripts/jquery-3.4.1.min.js"></script>
<script>
    $(function(){
        $("#h1").html("Hello world!");
        
    });
</script>
這裡要注意的是前端相對路徑,這裡我用的是 "../",這得依照你實際的路徑設定

 

ChromiumWebBrowser 讀取 Index.html

var fileName = Path.Combine(Directory.GetCurrentDirectory(), "Views/Index.html");
 
var browser = new ChromiumWebBrowser(fileName)
{
    Dock = DockStyle.Fill
};
this.Controls.Add(browser);

 

Content、Scripts、Views 這些前端檔案不會輸出到 bin 資料夾,可以一個檔案一個檔案設定

或者是用指令複製整個資料夾

@ .NET Framework

xcopy /s /y $(ProjectDir)Content $(TargetDir)Content\
xcopy /s /y $(ProjectDir)Scripts $(TargetDir)Scripts\
xcopy /s /y $(ProjectDir)Views $(TargetDir)Views\
 

@ .NET Core

新版的 nuget 已經不會把 package 放到專案,而是使用本機的快取路徑 %userprofile%/.nuget/packages,所以要到那裏去把 CSS、JS 檔案複製到 bin 資料夾

xcopy /s /y "%userprofile%/.nuget/packages/jquery/3.4.1/Content/Scripts" $(TargetDir)Scripts\
xcopy /s /y "%userprofile%/.nuget/packages/bootstrap/4.4.1/content/Scripts" $(TargetDir)Scripts\
xcopy /s /y "%userprofile%/.nuget/packages/bootstrap/4.4.1/content/Content" $(TargetDir)Content\
xcopy /s /y $(ProjectDir)Views $(TargetDir)Views\

 

運行結果,如下圖:

 

建置 Any CPU 平台

CefSharp 從 51 版本以後即支援 Any CPU 的編譯,官方提供了兩種方式定義 Any CPU 編譯,你可以選擇其中一種來設定,請參考:https://github.com/cefsharp/CefSharp/issues/1714

在專案定義裡面增加 <CefSharpAnyCpuSupport>true</CefSharpAnyCpuSupport>,如下圖所示

 

在 Program.cs 添加以下代碼

/// <summary>
///     The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += Resolver;
    InitializeCefSharp();
 
    var browser = new LoadHtmlForm();
    Application.Run(browser);
}
 
[MethodImpl(MethodImplOptions.NoInlining)]
private static void InitializeCefSharp()
{
    var settings = new CefSettings();
 
    // Set BrowserSubProcessPath based on app bitness at runtime
    // .NET Core 註解這一行
    settings.BrowserSubprocessPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
                                                  Environment.Is64BitProcess ? "x64" : "x86",
                                                  "CefSharp.BrowserSubprocess.exe");
 
    // Make sure you set performDependencyCheck false
    Cef.Initialize(settings, false, browserProcessHandler: null);
}
 
// Will attempt to load missing assembly from either x86 or x64 subdir
private static Assembly Resolver(object sender, ResolveEventArgs args)
{
    if (args.Name.StartsWith("CefSharp"))
    {
        var assemblyName = args.Name.Split(new[] {','}, 2)[0] + ".dll";
        var archSpecificPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
                                            Environment.Is64BitProcess ? "x64" : "x86",
                                            assemblyName);
 
        return File.Exists(archSpecificPath)
                   ? Assembly.LoadFile(archSpecificPath)
                   : null;
    }
 
    return null;
}

 

專案範例

https://github.com/yaochangyu/sample.dotblog/tree/master/CEF/Lab.Startup

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo