1. 前言
随着 Web 技术的发展,使用网页内容(HTML、JavaScript、CSS 等)作为桌面应用程序的一部分变得越来越常见。在 C# WinForm 中,Microsoft 提供的 WebView2 控件让我们可以轻松地嵌入 Chromium 浏览器,并实现 C# 与 JavaScript 的互操作。本文将详细介绍如何在 WinForm 项目中集成 WebView2 控件,并实现 C# 和 JavaScript 的双向调用。
2. 前置准备
- 安装 WebView2 Runtime(Windows 11 默认包含)。
- 在项目中添加 WebView2 控件。
- 安装 Microsoft.Web.WebView2 NuGet 包,以支持 WebView2 控件的功能。
3. 初始化 WebView2 控件
在 WinForm 中添加 WebView2 控件并初始化,确保其加载本地或远程的 HTML 文件。
using Microsoft.Web.WebView2.Core;
using System;
using System.Windows.Forms;
namespace WebView2InteropDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
InitializeAsync();
}
private async void InitializeAsync()
{
await webView21.EnsureCoreWebView2Async(null);
string htmlFilePath = System.IO.Path.Combine(AppContext.BaseDirectory, "index.html");
webView21.Source = new Uri($"file:///{htmlFilePath.Replace("\\", "/")}");
}
}
}
4. JavaScript 调用 C# 方法
实现 JavaScript 调用 C# 的方法需要以下几个步骤:
- 注册一个 C# 对象,使得 JavaScript 可以访问。
- 在 C# 中实现可以调用的公开方法。
- 在 JavaScript 中通过
window.chrome.webview.postMessage
向 C# 发送消息。
C# 端代码
在 WebView2 初始化完成后,可以向 JavaScript 注入一个 C# 对象,提供供调用的方法:
// C# 代码:注册可供 JavaScript 调用的对象
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
InitializeAsync();
}
private async void InitializeAsync()
{
await webView21.EnsureCoreWebView2Async(null);
webView21.CoreWebView2.WebMessageReceived += WebView2_WebMessageReceived;
string htmlFilePath = System.IO.Path.Combine(AppContext.BaseDirectory, "index.html");
webView21.Source = new Uri($"file:///{htmlFilePath.Replace("\\", "/")}");
}
private void WebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
{
string message = e.WebMessageAsJson; // 获取来自 JavaScript 的消息
MessageBox.Show("Received message from JavaScript: " + message);
}
// 向 JavaScript 发送消息的 C# 方法
public void SendMessageToJavaScript(string message)
{
webView21.CoreWebView2.PostWebMessageAsString(message);
}
}
JavaScript 端代码
在 HTML 文件中,通过 window.chrome.webview.postMessage
向 C# 发送消息。首先确保页面加载后,C# 已成功注册监听事件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView2 JS to C# Interop</title>
</head>
<body>
<h1>JavaScript to C# Interop</h1>
<button onclick="sendMessageToCSharp()">Send Message to C#</button>
<script>
function sendMessageToCSharp() {
// 通过 WebView2 的 postMessage 将消息发送给 C#
window.chrome.webview.postMessage("Hello from JavaScript!");
}
</script>
</body>
</html>
在此示例中,点击按钮将调用 JavaScript 中的 sendMessageToCSharp()
函数,该函数通过 window.chrome.webview.postMessage
向 C# 发送消息,C# 收到消息后在弹窗中显示接收到的内容。
5. C# 调用 JavaScript 方法
在某些情况下,我们希望从 C# 向 JavaScript 发送消息或调用 JavaScript 函数。可以使用 ExecuteScriptAsync
方法实现此功能。
C# 端代码
在 C# 端调用 ExecuteScriptAsync
来执行 JavaScript 代码:
// C# 代码:向 JavaScript 发送消息
public void CallJavaScriptFunction()
{
string script = "displayMessageFromCSharp('Hello from C#');";
webView21.CoreWebView2.ExecuteScriptAsync(script);
}
JavaScript 端代码
在 JavaScript 中实现一个函数,用于处理 C# 传递的数据:
<script>
function displayMessageFromCSharp(message) {
alert("Message from C#: " + message);
}
</script>
当 C# 调用 CallJavaScriptFunction
方法时,将执行 JavaScript 函数 displayMessageFromCSharp
,并弹出一个消息框显示从 C# 传递的消息。
6. 交互过程总结
- JavaScript 调用 C#:
- 通过使用
window.chrome.webview.postMessage
将消息发送到 C#。 - C# 使用
WebMessageReceived
事件接收消息,并在需要时执行相应操作。
- C# 调用 JavaScript:
- 通过使用
ExecuteScriptAsync
方法执行 JavaScript 代码。 - JavaScript 端实现处理函数,接受从 C# 传递的消息或参数,并做出响应。
7.完整项目构建汇总
1、新增项目WebView2InteropDemo,并且引入依赖库
引入依赖库
根据操作系统版本,引入WebView2.Runtime.X64
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>disable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="WebView2.Runtime.X64" Version="130.0.2849.80" />
</ItemGroup>
<ItemGroup>
<None Update="index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
2、新增Form1窗体,构建布局
Form1.Designer.cs代码
namespace WebView2InteropDemo
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
webView21 = new Microsoft.Web.WebView2.WinForms.WebView2();
btnCallJsFunc = new Button();
((System.ComponentModel.ISupportInitialize)webView21).BeginInit();
SuspendLayout();
//
// webView21
//
webView21.AllowExternalDrop = true;
webView21.CreationProperties = null;
webView21.DefaultBackgroundColor = Color.White;
webView21.Dock = DockStyle.Fill;
webView21.Location = new Point(0, 34);
webView21.Name = "webView21";
webView21.Size = new Size(800, 416);
webView21.TabIndex = 0;
webView21.ZoomFactor = 1D;
//
// btnCallJsFunc
//
btnCallJsFunc.Dock = DockStyle.Top;
btnCallJsFunc.Location = new Point(0, 0);
btnCallJsFunc.Name = "btnCallJsFunc";
btnCallJsFunc.Size = new Size(800, 34);
btnCallJsFunc.TabIndex = 1;
btnCallJsFunc.Text = "Call Js Func";
btnCallJsFunc.UseVisualStyleBackColor = true;
btnCallJsFunc.Click += btnCallJsFunc_Click;
//
// Form1
//
AutoScaleDimensions = new SizeF(11F, 24F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(webView21);
Controls.Add(btnCallJsFunc);
Name = "Form1";
StartPosition = FormStartPosition.CenterScreen;
Text = "Form1";
((System.ComponentModel.ISupportInitialize)webView21).EndInit();
ResumeLayout(false);
}
#endregion
private Microsoft.Web.WebView2.WinForms.WebView2 webView21;
private Button btnCallJsFunc;
}
}
Form1.cs
using Microsoft.Web.WebView2.Core;
namespace WebView2InteropDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
InitializeAsync();
}
private async void InitializeAsync()
{
await webView21.EnsureCoreWebView2Async(null);
webView21.CoreWebView2.WebMessageReceived += WebView2_WebMessageReceived;
string htmlFilePath = System.IO.Path.Combine(AppContext.BaseDirectory, "index.html");
webView21.Source = new Uri($"file:///{htmlFilePath.Replace("\\", "/")}");
}
private void WebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
{
string message = e.WebMessageAsJson;
MessageBox.Show("Received message from JavaScript: " + message);
}
public void SendMessageToJavaScript(string message)
{
webView21.CoreWebView2.PostWebMessageAsString(message);
}
public void CallJavaScriptFunction()
{
string script = "displayMessageFromCSharp('Hello from C#');";
webView21.CoreWebView2.ExecuteScriptAsync(script);
}
private void btnCallJsFunc_Click(object sender, EventArgs e)
{
CallJavaScriptFunction();
}
}
}
3、编写html内嵌web网页代码
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView2 JS to C# Interop</title>
</head>
<body>
<h1>JavaScript to C# Interop</h1>
<button onclick="sendMessageToCSharp()">Send Message to C#</button>
<script>
function sendMessageToCSharp() {
window.chrome.webview.postMessage("Hello from JavaScript!");
}
function displayMessageFromCSharp(message) {
alert("Message from C#: " + message);
}
</script>
</body>
</html>
4、执行结果
JS函数调C#函数代码
C#函数调用JS函数
8.总结
WebView2 的互操作功能使我们能够将现代 Web 技术无缝集成到 WinForm 应用程序中。通过本文介绍的方法,可以实现 JavaScript 和 C# 的双向调用,使得 WinForm 应用程序可以有效地利用 Web 内容和桌面功能,满足更复杂的业务需求。