教你在.Net8.0的WinForm中使用WebView2,实现C#和JavaScript的实时双向互操作

1. 前言

随着 Web 技术的发展,使用网页内容(HTML、JavaScript、CSS 等)作为桌面应用程序的一部分变得越来越常见。在 C# WinForm 中,Microsoft 提供的 WebView2 控件让我们可以轻松地嵌入 Chromium 浏览器,并实现 C# 与 JavaScript 的互操作。本文将详细介绍如何在 WinForm 项目中集成 WebView2 控件,并实现 C# 和 JavaScript 的双向调用。

2. 前置准备

  1. 安装 WebView2 Runtime(Windows 11 默认包含)。
  2. 在项目中添加 WebView2 控件。
  3. 安装 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# 的方法需要以下几个步骤:

  1. 注册一个 C# 对象,使得 JavaScript 可以访问。
  2. 在 C# 中实现可以调用的公开方法。
  3. 在 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. 交互过程总结

  1. JavaScript 调用 C#
  • 通过使用 window.chrome.webview.postMessage 将消息发送到 C#。
  • C# 使用 WebMessageReceived 事件接收消息,并在需要时执行相应操作。
    1. 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 内容和桌面功能,满足更复杂的业务需求。

    作者:web13595609705

    物联沃分享整理
    物联沃-IOTWORD物联网 » 教你在.Net8.0的WinForm中使用WebView2,实现C#和JavaScript的实时双向互操作

    发表回复