c#form的WebView2组件与窗体相互交互完整代码

我在此提供两个类可以直接完成他们的交互

using System.Windows.Forms;
using System;
using System.Runtime.InteropServices;
using Microsoft.Web.WebView2.WinForms;
using System.Threading.Tasks;
using Microsoft.Web.WebView2.Core;
using System.IO;
using System.Text;

    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class AppBridgeBase
    {
        public WebView2 webView;
        protected string wn = "InternalWeb";
        protected string wf = "index.html";
        private AppBridge bridge;

        protected async void InitializeAsync(AppBridge bridge)
        {
            try
            {
                this.bridge = bridge;
                var env = await CoreWebView2Environment.CreateAsync(); //创建环境
                await bridge.webView.EnsureCoreWebView2Async(env);//等待WebView2初始化完成
                if (bridge.webView.CoreWebView2 == null)
                {
                    MessageBox.Show("CoreWebView2初始化失败");
                    return;
                }
                RegisterAppBridge();
                //加载本地内容
                string htmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, wn, wf);
                bridge.webView.CoreWebView2.Navigate(new Uri(htmlPath).AbsoluteUri);

            }
            catch (Exception err) { MessageBox.Show($"初始化错误: {err.Message}"); }
        }
        /// <summary>
        ///  注册桥接对象
        /// </summary>
        private void RegisterAppBridge()
        {
            try
            {
                if (bridge.webView.InvokeRequired)
                {
                    bridge.webView.Invoke((MethodInvoker)RegisterAppBridge);
                    return;
                }
                if (bridge.webView.CoreWebView2 != null)
                {
                    try
                    {
                        bridge.webView.CoreWebView2.RemoveHostObjectFromScript("bridge");
                    }
                    catch { }
                    // 注册新对象
                    bridge.webView.CoreWebView2.AddHostObjectToScript("bridge", bridge);
                    // 确认注册成功
                    //webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("alert(\"注册成功\");");
                    // 订阅 WebMessageReceived 事件
                    bridge.webView.CoreWebView2.WebMessageReceived += CoreWebView2_WebMessageReceived;
                }
            }
            catch (Exception err)
            {
                MessageBox.Show($"注册桥接对象失败: {err.Message}");
            }
        }
        private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
        {
            string message = e.TryGetWebMessageAsString();
            bridge.WebMessageReceived(message);
        }

        /// <summary>
        /// 发送信息通知
        /// </summary>
        public virtual async Task SendNotice(string info)
        {
            await webView.CoreWebView2.ExecuteScriptAsync("alert(\"来自客户端的消息:{\n" + info + "\n}\");");
        }
        /// <summary>
        /// c#调用web中的js函数
        /// </summary>
        public async Task RunWebFunctionAsync(string fun)
        {
            await webView.CoreWebView2.ExecuteScriptAsync(fun);
        }
        /// <summary>
        /// 接受来自网页的消息
        /// </summary>
        public virtual void WebMessageReceived(string message)
        {
            //MessageBox.Show($"接收Web消息: {message}");//监听功能,建议重载
        }
        /// <summary>
        /// 获取版本信息
        /// </summary>
        public virtual string GetAppInfo()
        {
            return $"应用程序信息\n产品名称: " + Application.ProductName + "\n版本: " + Application.ProductVersion + "";
        }
        /// <summary>
        /// web调用c#测试
        /// </summary>
        /// <param name="message">web传递的信息</param>
        public virtual void TestMessage(string message) { MessageBox.Show(message, "来自JavaScript的消息"); }
        /// <summary>
        /// c#测试调用web
        /// </summary>
        /// <param name="message">传递给web的信息</param>
        public virtual void TestSendMessage(string message) { RunWebFunctionAsync("test("+message+");"); }
        /// <summary>
        /// 创建默认路径默认网页模板
        /// </summary>
        public static AppBridge CreateTemplateTest(WebView2 web2)
        {
            Directory.CreateDirectory(AppDomain.CurrentDomain.BaseDirectory + "InternalWeb\\");
            string web = @"<!DOCTYPE html>"+"\n"+
"<html lang=" + '"' + "zh-CN" + '"' + ">\n" +
    "<head>\n" +
        "<meta charset=" + '"' + "UTF-8" + '"' + ">\n" +
        "<meta name=" + '"' + "viewport" + '"' + " content=" + '"' + "width=device-width, initial-scale=1.0" + '"' + ">\n" +
        "<title>模板</title>\n" +
        "<!-- <link rel=" + '"' + "stylesheet" + '"' + " href=" + '"' + "style.css" + '"' + "> -->\n" +
    "</head>\n" +
    "<body>\n" +
        "<!-- <script src=" + '"' + "script.js" + '"' + "></script> -->\n" +
        "<div id = 'butt' style = 'background-color: aquamarine;width: 100px height: 100px;' > 点击调用c#函数获取消息 </div>\n"+
            "<script>\n" +
        "document.getElementById('butt').addEventListener('click', async () => {\n" +
            "//window.chrome.webview.postMessage('按钮点击事件');\n//向c#发送消息(c#的监听(WebMessageReceived)功能可以接收此信息)\n" +
            "const info = await window.chrome.webview.hostObjects.bridge.GetAppInfo(); //如果c#函数没有返回值则不需要当成变量使用\n" +
            "document.getElementById('butt').innerText = info;\n" +
       " });\n" +
       "function test(a){ document.getElementById('butt').innerText = a; }"+
            "</script>\n" +
    "</body>\n" +
"</html>\n";
            if (!File.Exists(AppDomain.CurrentDomain.BaseDirectory + "InternalWeb\\index.html"))
            {
                File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "InternalWeb\\index.html", web, Encoding.UTF8);
            }
            else
            {
                //提示作用
                MessageBox.Show(AppDomain.CurrentDomain.BaseDirectory + "InternalWeb\\index.html"+"该文件已存在,无法创建默认网页");
            }
            return new AppBridge(web2);
        }
    }
    [ClassInterface(ClassInterfaceType.AutoDual)]//必须
    [ComVisible(true)]//必须
    // 桥接类实现
    public class AppBridge:AppBridgeBase
    {
        /// <summary>
        /// 创建链接web的桥
        /// </summary>
        /// <param name="web">WebView2组件</param>
        /// <param name="webName">启动文件目录下的网页存放根目录</param>
        /// <param name="webFile">网页文件</param>
        public AppBridge(WebView2 web, string webName = "InternalWeb", string webFile = "index.html")
        {
            Directory.CreateDirectory(AppDomain.CurrentDomain.BaseDirectory + "InternalWeb\\");
            webView = web;
            wn = webName;
            wf = webFile;
            InitializeAsync(this);
        }

        /**********************下面则添加web需要调用与被调用的函数*************************/
        /// <summary>
        /// web调用的函数
        /// </summary>
        public string GetAppInfo()
        {
            return $"应用程序信息\n产品名称: " + Application.ProductName + "\n版本: " + Application.ProductVersion + "";
        }
        /// <summary>
        /// c#调用web函数
        /// </summary>
        /// <param name="message">js函数</param>
        public virtual void SendMessage(string message) { RunWebFunctionAsync("test(" + message + ");"); }
    }

用此方法创建即可使用

            bridge = AppBridge.CreateTemplateTest(webView);//代码中只带了相应的网页代码,或者自己创建,则可以AppBridge bridge =new AppBridge(webView);即可。

后续直接在AppBridge类里面添加web需要的功能函数。

新加完整,可以下面为准

public class InternalWeb
{
    private string root = "";
    private WebView2 webView;
    private string name;
    private object bridge;
    /// <summary>
    /// 桥
    /// </summary>
    /// <param name="web">WebView2</param>
    /// <param name="webRootPath">网页根目录</param>
    /// <param name="bridgeName">桥接名称</param>
    /// <param name="bridgeClass">桥接类</param>
    public InternalWeb(WebView2 web,string webFilePath,string bridgeName,object bridgeClass) { bridge = bridgeClass; name = bridgeName; webView = web;root = webFilePath; InitializeAsync(); }
    private async void InitializeAsync()
    {
        try
        {
            var env = await CoreWebView2Environment.CreateAsync();
            webView.CoreWebView2InitializationCompleted += WebView_CoreWebView2InitializationCompleted;
            await webView.EnsureCoreWebView2Async(env);
            if (!File.Exists(root)) { MessageBox.Show("找不到网页文件:" + root); }
            webView.Source = new Uri(root);
        }
        catch (Exception err) { MessageBox.Show($"初始化错误: {err.Message}"); }
    }
    private void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
    {
        if (e.IsSuccess)
        {
            webView.CoreWebView2.WebMessageReceived += CoreWebView2_WebMessageReceived;
            webView.CoreWebView2.AddHostObjectToScript(name, bridge);
        }
        else
        {
            MessageBox.Show($"WebView2 初始化失败: {e.InitializationException?.Message}");
        }
    }
    private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
    {
        // 接收来自网页的消息 
        string message = e.TryGetWebMessageAsString();
        MessageBox.Show("接受来自网页的消息:"+message);
    }
    /// <summary>
    /// 更换网页
    /// </summary>
    /// <param name="url">本地网页文件</param>
    private List<string> funKV = new List<string>();
    public void setUrl(Uri url) { webView.Source = url; funKV.Clear();}
    /// <summary>
    /// 向网页发送消息
    /// </summary>
    public void SendMessage(string info)
    {
        if (webView.CoreWebView2 != null)
        {
            webView.CoreWebView2.PostWebMessageAsString(info);
        }
        else
        {
            MessageBox.Show("WebView2 尚未初始化完成");
        }
    }
    /// <summary>
    /// 调用网页js函数可有返回值
    /// </summary>
    /// <param name="txtJsFunction">函数</param>
    public async Task<string> RunWebFunctionAsync(string txtJsFunction)
    {
        if (!funKV.Contains(txtJsFunction))
        {
            funKV.Add(txtJsFunction);
            if (webView.CoreWebView2 != null)
            {
                try
                {
                    string result = await webView.CoreWebView2.ExecuteScriptAsync(txtJsFunction);
                    funKV.Remove(txtJsFunction);
                    return result;
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"调用 JS 函数出错: {ex.Message}\r\n");
                    return null;
                }
            }
            else
            {
                MessageBox.Show("WebView2 尚未初始化完成");
                return null;
            }
        }
        return null;
    }
    /// <summary>
    /// 添加桥
    /// </summary>
    /// <param name="_bridgeName">桥名称</param>
    /// <param name="_bridgeClass">桥类</param>
    public void AddObjectToScript(string _bridgeName,object _bridgeClass)
    {
        webView.CoreWebView2.AddHostObjectToScript(_bridgeName, _bridgeClass);
    }
    /// <summary>
    /// 资源释放
    /// </summary>
    public void Dispose()
    {
        if (webView != null)
        {
            if (webView.CoreWebView2 != null)
            {
                webView.CoreWebView2.WebMessageReceived -= CoreWebView2_WebMessageReceived;
                webView.CoreWebView2InitializationCompleted -= WebView_CoreWebView2InitializationCompleted;
            }
            webView.Dispose();
            webView = null;
        }
    }
}

桥类

    [ClassInterface(ClassInterfaceType.AutoDual)]//必备
    [ComVisible(true)]//必备
    public class Bridge
    {
        // JavaScript 可以调用的方法
        public void ShowMessage(string message)
        {
            MessageBox.Show($"JavaScript  调用 C# 方法: {message}");
        }

        // 另一个可以被 JavaScript 调用的方法
        public string GetCurrentTime()
        {
            //return $"应用程序信息\n产品名称: " + Application.ProductName + "\n版本: " + Application.ProductVersion + "";
            return DateTime.Now.ToString();
        }
    }

使用方法

InternalWeb bridge =new InternalWeb(webView, "C:\\Users\\Administrator\\Desktop\\Foresee\\bin\\Debug\\InternalWeb\\index2.html", "bridge", new Bridge());

网页代码

<script>
    // 接收来自 C# 的消息 
    window.chrome.webview.addEventListener('message',  event => {
        logMessage(`来自 C# 的消息: ${event.data}`); 
    });
    
    // 发送消息到 C#
    function sendMessageToCSharp() {
        const message = document.getElementById('messageInput').value; 
        window.chrome.webview.postMessage(message); 
        logMessage(`发送到 C# 的消息: ${message}`);
    }
    
    // 调用 C# 方法 
    function callCSharpMethod() {
        const message = "Hello from JavaScript";
        window.chrome.webview.hostObjects.bridge.ShowMessage(message); //bridge这个是使用方法里面填的名称相当于c#类后面的就是函数
            logMessage(`调用 C# 方法 ShowMessage("${message}")`);
        
    }
    
    // 调用 C# 方法并获取返回值
    async function getTimeFromCSharp() {
        try {
            var time = await window.chrome.webview.hostObjects.bridge.GetCurrentTime();
            logMessage(`调用 C# 方法 GetCurrentTime() 返回:` + time);
        } catch (error) {
            logMessage(`调用 C# 方法出错: ${error}`);
        }
    }
    
    // 供 C# 调用的 JavaScript 函数 
    function jsFunction(message) {
        logMessage(`C# 调用了 jsFunction("${message}")`);
        return `JavaScript 收到了: ${message}`;
    }
// 记录消息到日志
function logMessage(message) {
    const log = document.getElementById('messageLog'); 
    log.innerHTML  += `${message}<br>`;
    log.scrollTop  = log.scrollHeight; 
}

### C# 中使用 WebView2 的案例 #### 创建并初始化 WebView2 控件 为了在 C# 应用程序中集成 WebView2,首先需要安装 Microsoft.Web.WebView2 NuGet 包。这可以通过 Visual Studio 或者命令行工具完成。 ```csharp using Microsoft.Web.WebView2.WinForms; using System.Windows.Forms; public class MainForm : Form { private WebView2 webView; public MainForm() { webView = new WebView2(); webView.Dock = DockStyle.Fill; Controls.Add(webView); InitializeAsync(); } async void InitializeAsync() { await webView.EnsureCoreWebView2Async(null); webView.CoreWebView2.Navigate("https://www.example.com"); } } ``` 此代码片段展示了如何创建 `WebView2` 实例,并将其设置为窗体的一部分[^2]。通过调用 `EnsureCoreWebView2Async()` 方法异步加载 WebView2 运行时环境,并导航到指定 URL 地址。 #### 处理 JavaScript 对话框和其他浏览器事件 当网页请求显示对话框或其他交互式提示时,可以利用 `WebMessageReceived` 事件监听器来接收来自页面的消息: ```csharp webView.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false; webView.CoreWebView2.ScriptDialogOpening += (sender, args) => { MessageBox.Show(args.Message); args.Handled = true; }; ``` 上述配置禁用了默认脚本对话框,并自定义了一个消息框用于替代原生弹窗行为。 #### 加载本地 HTML 文件 如果希望加载位于应用程序资源中的静态HTML文件,则可通过以下方式实现路径转换访问权限授予: ```csharp string htmlFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "index.html"); // Grant file access permission to the folder containing index.html. await webView.CoreWebView2.Environment.SystemEnvironment.FileUtilities.GrantFileAccessToCurrentProcessAsync(htmlFilePath); webView.Source = new Uri($"file://{htmlFilePath}"); ``` 这段代码说明了怎样读取本地磁盘上的HTML文档作为初始页面源码。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值