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);}#endregionprivate 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 内容和桌面功能,满足更复杂的业务需求。