零、参考资料
1、https://github.com/cefsharp/CefSharp/wiki/Quick-Start-For-MS-.Net-5.0-or-greater
2、https://github.com/cefsharp/CefSharp/wiki/Quick-Start
3、https://github.com/cefsharp/CefSharp/wiki/General-Usage#javascript-integration
一、安装 Nuget 包
https://www.nuget.org/packages/CefSharp.WinForms
安装 CefSharp.WinForms 包后会显示 Readme.txt,
二、配置项目
<!-- CefWindowsFormsApp.csproj -->
<PropertyGroup Condition="'$(PlatformTarget)' == 'x64'">
<RuntimeIdentifier Condition="'$(RuntimeIdentifier)' == ''">win-x64</RuntimeIdentifier>
<SelfContained Condition="'$(SelfContained)' == ''">false</SelfContained>
</PropertyGroup>
三、加载远程网页示例
使用 ChromiumWebBrowser 加载百度首页,
// Form1.cs
using CefSharp;
using CefSharp.WinForms;
using System.Windows.Forms;
namespace CefWindowsFormsApp
{
public partial class Form1 : Form
{
private static ChromiumWebBrowser browser;
public Form1()
{
InitializeComponent();
AddChromiumWebBrowser();
}
/// <summary>
/// Create a new instance in code or add via the designer
/// </summary>
private void AddChromiumWebBrowser()
{
browser = new ChromiumWebBrowser("www.baidu.com");
this.Controls.Add(browser);
}
private void Form1_Load(object sender, System.EventArgs e)
{
// Load a url
browser.LoadUrl("https://www.baidu.com/");
}
}
}
这这个示例中,我们引入了 CefSharp 库,在 Form1 窗体中添加了浏览器控件 ChromiumWebBrowser ,并且在窗体启动时加载百度首页,
四、加载本地网页示例
首先创建一个 Vue 项目,
# 使用 Vite
cnpm create vite@latest
# cd vite-project
# cnpm i
接着完成前端的开发之后,打包静态资源,
npm run build
然后在 WinForm 项目下创建 Resources 文件夹,把前端打包的 dist 文件夹下的文件全部复制过来,并且文件属性设置为“嵌入的资源”,
最后通过 RegisterScheme 注册为本地资源访问,
// Form1.cs
using CefSharp;
using CefSharp.SchemeHandler;
using CefSharp.WinForms;
using System.Windows.Forms;
namespace CefWindowsFormsApp
{
public partial class Form1 : Form
{
private static ChromiumWebBrowser browser;
public Form1()
{
InitializeComponent();
AddChromiumWebBrowser();
}
/// <summary>
/// Create a new instance in code or add via the designer
/// </summary>
private void AddChromiumWebBrowser()
{
InitBrowser();
browser = new ChromiumWebBrowser("http://cefsharp.test");
this.Controls.Add(browser);
}
public static void InitBrowser()
{
// Pseudo code; you probably need more in your CefSettings also.
var settings = new CefSettings();
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = "http",
DomainName = "cefsharp.test",
SchemeHandlerFactory = new FolderSchemeHandlerFactory(rootFolder: @"..\..\..\..\CefWindowsFormsApp\Resources",
hostName: "cefsharp.test", //Optional param no hostname/domain checking if null
defaultPage: "index.html") //Optional param will default to index.html
});
Cef.Initialize(settings);
}
private void Form1_Load(object sender, System.EventArgs e)
{
// Load local url
browser.LoadUrl("http://cefsharp.test");
}
}
}
效果如下,
五、调用 JS 代码
1、JS 无返回值
窗体页面调整,新增一个 Button 、一个 Pane,
注意,JavaScript 只能在 V8Context 中执行,这里的示例通过实现 IRenderProcessMessageHandler 接口、绑定 LoadingStateChanged 、FrameLoadEnd 两个事件来实现 DOM 加载时弹窗、页面资源加载完毕弹窗、主页面加载完毕弹窗,通过 “DoAlert” 按钮绑定事件来实现手动弹窗,
// Form1.cs
using CefSharp;
using CefSharp.SchemeHandler;
using CefSharp.WinForms;
using System.Windows.Forms;
namespace CefWindowsFormsApp
{
public partial class Form1 : Form
{
private static ChromiumWebBrowser browser;
public Form1()
{
InitializeComponent();
AddChromiumWebBrowser();
}
/// <summary>
/// Create a new instance in code or add via the designer
/// </summary>
private void AddChromiumWebBrowser()
{
InitBrowser();
browser = new ChromiumWebBrowser("http://cefsharp.test");
browser.RenderProcessMessageHandler = new RenderProcessMessageHandler();
// Wait for the page to finish loading (all resources will have been loaded, rendering is likely still happening)
browser.LoadingStateChanged += (sender, args) =>
{
// Wait for the Page to finish loading
if (args.IsLoading == false)
{
browser.ExecuteScriptAsync("alert('All Resources Have Loaded');");
}
};
// Wait for the MainFrame to finish loading
browser.FrameLoadEnd += (sender, args) =>
{
// Wait for the MainFrame to finish loading
if (args.Frame.IsMain)
{
args.Frame.ExecuteJavaScriptAsync("alert('MainFrame finished loading');");
}
};
BrowserPanel.Controls.Add(browser);
}
public static void InitBrowser()
{
// Pseudo code; you probably need more in your CefSettings also.
var settings = new CefSettings();
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = "http",
DomainName = "cefsharp.test",
SchemeHandlerFactory = new FolderSchemeHandlerFactory(rootFolder: @"..\..\..\..\CefWindowsFormsApp\Resources",
hostName: "cefsharp.test", // Optional param no hostname/domain checking if null
defaultPage: "index.html") // Optional param will default to index.html
});
Cef.Initialize(settings);
}
private void Form1_Load(object sender, System.EventArgs e)
{
// Load a url
browser.LoadUrl("http://cefsharp.test");
}
public class RenderProcessMessageHandler : IRenderProcessMessageHandler
{
public void OnContextReleased(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame)
{
throw new System.NotImplementedException();
}
public void OnFocusedNodeChanged(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IDomNode node)
{
throw new System.NotImplementedException();
}
public void OnUncaughtException(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, JavascriptException exception)
{
throw new System.NotImplementedException();
}
// Wait for the underlying JavaScript Context to be created. This is only called for the main frame.
// If the page has no JavaScript, no context will be created.
void IRenderProcessMessageHandler.OnContextCreated(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
const string script = "document.addEventListener('DOMContentLoaded', function(){ alert('DomLoaded'); });";
frame.ExecuteJavaScriptAsync(script);
}
}
private void DoAlertBtn_Click(object sender, System.EventArgs e)
{
browser.ExecuteScriptAsync("alert('Hello World!');");
}
}
}
效果如下,
2、JS 有返回值
private async void DoAlertBtn_ClickAsync(object sender, System.EventArgs e)
{
var script = @"(function() { let val = 1 + 1; return val; })();";
JavascriptResponse response = await browser.GetBrowser().MainFrame.EvaluateScriptAsync(script);
browser.ExecuteScriptAsync(string.Format("alert(' 1 + 1 = {0}');", (int)response.Result));
}
六、Browser 调试器
browser.ShowDevTools();
七、app.manifest 清单文件
该清单文件是为了兼容 Win7、8、10 等系统差异,
<!-- example.exe.manifest -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity
type="win32"
name="Contoso.ExampleApplication.ExampleBinary"
version="1.2.3.4"
processorArchitecture="x86"
/>
<description>Contoso Example Application</description>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10/11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> <!-- * ADD THIS LINE * -->
</application>
</compatibility>
</assembly>
八、发布
项目右键,选择 Release x64 模式“重新生成”,在 bin 目录下生成文件,
需要把该目录的所有文件复制到另一台相同 .Net 版本的电脑才能运行。