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

news2024/11/24 2:47:22

在这里插入图片描述

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2237135.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何安装QT(linux/windows)

1. linux 1.1 下载安装程序 进入QT官网&#xff0c;点击右上角下载 Qt | Tools for Each Stage of Software Development Lifecycle​www.qt.io/ 然后选择下载linux版本&#xff0c;这里你需要填写一些信息&#xff0c;注册一些即可 填写之后会出现下面这个网页&#xff0c;…

PVE纵览-PVE与VM:谁才是你的最佳虚拟化选择?

PVE纵览-PVE与VM&#xff1a;谁才是你的最佳虚拟化选择&#xff1f; 文章目录 PVE纵览-PVE与VM&#xff1a;谁才是你的最佳虚拟化选择&#xff1f;摘要1 不同虚拟化平台的基础2 平台特性与功能3 性能与可靠性4 成本与经济性5 应用场景比较6 用户体验与支持7 结论与建议 关键字&…

C/C++语言基础--C++模板与元编程系列四(类型模板参数、整数、指针 、模板类型)

本专栏目的 更新C/C的基础语法&#xff0c;包括C的一些新特性 前言 模板与元编程是C的重要特点&#xff0c;也是难点&#xff0c;本人预计将会更新10期左右进行讲解&#xff0c;这是第四期&#xff0c;有些和前面三期重合&#xff0c;这一期也是为明天更新打下基础&#xff…

数据结构:顺序表(动态顺序表)

专栏说明&#xff1a;本专栏用于数据结构复习&#xff0c;文章中出现的代码由C语言实现&#xff0c;在专栏中会涉及到部分OJ题目&#xff0c;如对你学习有所帮助&#xff0c;可以点赞鼓励一下博主喔&#x1f493; 博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;数…

力扣动态规划基础版(矩阵型)

62.不同路径&#xff08;唯一路径问题&#xff09; 62. 不同路径https://leetcode.cn/problems/unique-paths/ 方法一&#xff1a;动态规划 找状态转移方程&#xff0c;也就是说它从左上角走到右下角&#xff0c;只能往右或者往下走&#xff0c;那么设置一个位置为&#xff…

音视频入门基础:FLV专题(23)——FFmpeg源码中,获取FLV文件音频信息的实现(下)

音视频入门基础&#xff1a;FLV专题系列文章&#xff1a; 音视频入门基础&#xff1a;FLV专题&#xff08;1&#xff09;——FLV官方文档下载 音视频入门基础&#xff1a;FLV专题&#xff08;2&#xff09;——使用FFmpeg命令生成flv文件 音视频入门基础&#xff1a;FLV专题…

A021基于Spring Boot的自习室管理和预约系统设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

qt QShortcut详解

1、概述 QShortcut是Qt框架中的一个类&#xff0c;它提供了一种创建键盘快捷键的方式。通过QShortcut&#xff0c;开发者可以将特定的键盘组合&#xff08;如CtrlC、AltF4等&#xff09;与应用程序中的动作&#xff08;如复制、关闭窗口等&#xff09;关联起来。当用户在应用程…

注意力机制的目的:理解语义;编码器嵌入高纬空间计算;注意力得分“得到S*V”;解码器掩码和交叉注意力层用于训练;最终的编码器和输出实现大模型

目录 注意力机制的目的:理解语义中的它是小白兔 词编码器嵌入高纬空间 计算注意力得分“得到S*V” 权重QKV:连接权重 训练阶段使用解码器:翻译后的语句 解码器掩码和交叉注意力层用于训练 最终的编码器和输出实现大模型 Transformer模型中,QKV QKV的作用 举例说明…

jmeter常用配置元件介绍总结之取样器

系列文章目录 1.windows、linux安装jmeter及设置中文显示 2.jmeter常用配置元件介绍总结之安装插件 3.jmeter常用配置元件介绍总结之取样器 jmeter常用配置元件介绍总结之取样器 2.取样器2.1.HTTP请求2.2.Debug Sampler2.3.JSR223 Sampler2.4.JDBC Connection Configuration和J…

【大数据学习 | kafka】简述kafka的消费者consumer

1. 消费者的结构 能够在kafka中拉取数据进行消费的组件或者程序都叫做消费者。 这里面要涉及到一个动作叫做拉取。 首先我们要知道kafka这个消息队列主要的功能就是起到缓冲的作用&#xff0c;比如flume采集数据然后交给spark或者flink进行计算分析&#xff0c;但是flume采用的…

从零开始训练一个大语言模型需要多少天?

一&#xff0c;前言 在AI领域&#xff0c;训练一个大型语言模型&#xff08;LLM&#xff09;是一个耗时且复杂的过程。几乎每个做大型语言模型&#xff08;LLM&#xff09;训练的人都会被问到&#xff1a;“从零开始&#xff0c;训练大语言模型需要多久和花多少钱&#xff1f;”…

【SQL50】day 1

目录 1.可回收且低脂的产品 2.寻找用户推荐人 3.使用唯一标识码替换员工ID 4.产品销售分析 I 5.有趣的电影 6.平均售价 7.每位教师所教授的科目种类的数量 8.平均售价 1.可回收且低脂的产品 # Write your MySQL query statement below select product_id from Products w…

Qt菜单功能实现

本文介绍Qt菜单功能实现。 Qt开发过程中&#xff0c;菜单功能用的还是比较多的&#xff0c;本文针对菜单栏和右键菜单功能实现作简要描述。 1.菜单栏 1)界面设计 在界面中添加菜单栏&#xff08;本例中名为“menubar”&#xff09;&#xff0c;并依次添加需要的菜单&#x…

Jupyter Notebook添加kernel的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Java:二维数组

目录 1. 二维数组的基础格式 1.1 二维数组变量的创建 —— 3种形式 1.2 二维数组的初始化 \1 动态初始化 \2 静态初始化 2. 二维数组的大小 和 内存分配 3. 二维数组的不规则初始化 4. 遍历二维数组 4.1 for循环 ​编辑 4.2 for-each循环 5. 二维数组 与 方法 5.1…

手机内卷下一站,AI Agent

作者 | 辰纹 来源 | 洞见新研社 2024年除夕夜&#xff0c;OPPO在央视春晚即将开始前举办了一场“史上最短发布会”&#xff0c;OPPO首席产品官刘作虎宣布&#xff0c;“OPPO正式进入AI手机时代”。 春节假期刚过&#xff0c;魅族又公开表示&#xff0c;将停止“传统智能手机…

Python实战:调用淘宝API以抓取商品页面数据

在数据驱动的商业决策中&#xff0c;获取电商平台的商品数据至关重要。淘宝作为中国最大的在线购物平台&#xff0c;其商品数据对于市场分析、价格监控和竞品研究等方面都具有极高的价值。本文将通过一个Python实战案例&#xff0c;展示如何调用淘宝API来抓取商品页面的数据。 …

SpringBoot14-任务

任务 14.1异步任务 所谓异步&#xff0c;在某些功能实现时可能要花费一定的时间&#xff0c;但是为了不影响客户端的体验&#xff0c;选择异步执行 案例&#xff1a; 首先创建一个service&#xff1a; Service public class AsyncService {public void hello(){try {Threa…

如何在Android中自定义property

在Android中创建自定义的属性&#xff08;Android property&#xff09;通常用于调试、性能调优或传递应用和系统之间的信息。 以下是如何在Android中创建和使用自定义属性的步骤&#xff1a; 1. 定义属性 在Android中&#xff0c;属性是以“属性名称属性值”形式定义的键值对…