前言

目前的windows/Linux下的UI方案,以Qt为主,Flutter, Electron为辅,其他的各种UI都是不堪大用。众所周知,Electron的资源占用和内容占用太大,效率不行,所以有了后续各种跨语言的Web套壳方案:

  • walls go语言下web套壳
  • tarui Rust下的web套壳

除了使用CEF的Qt/C++/C#方案,Qt+WebEngine, 目前在Windows下各家的最终归路都转向Webview2方案,可以极大地减少发布的程序的大小。

备注:

  1. VS2019支持.Net Framework(~4.8), 对于Net Core 3 和Net 5 支持并不是很完善,并且已过了维护期
  2. VS2022对Net 6, 7以及Net Framework 4.8 的支持都很完善,建议使用此搭配

C# Winform下Webview2方案Demo

.Net Framework 使用4.8

UI Form核心Code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace webview
{
    public partial class Form1 : Form
    {
        private webTool tool;

        public Form1()
        {
            InitializeComponent();
            // https://blog.csdn.net/bashendixie5/article/details/126432821
            tool = new webTool(ref webView2_main);
            initWebview2();
        }

        private async void initWebview2()
        {
            var userData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Application.ProductName);
            var env = await Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(null, userData);
            await webView2_main.EnsureCoreWebView2Async(env);
            //webView2_main.CoreWebView2InitializationCompleted += WebView2_main_CoreWebView2InitializationCompleted;

            // title 发生变化时
            webView2_main.CoreWebView2.DocumentTitleChanged += CoreWebView2_DocumentTitleChanged;
            // 有新的网页请求时, 拦截
            webView2_main.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;

            // add binding with C#
            webView2_main.CoreWebView2.AddHostObjectToScript("tool", tool);
        }

        private void CoreWebView2_NewWindowRequested(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NewWindowRequestedEventArgs e)
        {
            var defer = e.GetDeferral();
            e.Handled = true; 
            webView2_main.Source = new Uri(e.Uri);
            // 或者新开一个windows
            //e.NewWindow = webView2_main.CoreWebView2;
            defer.Complete();
        }

        private void CoreWebView2_DocumentTitleChanged(object sender, object e)
        {
            Text = webView2_main.CoreWebView2.DocumentTitle;
        }

        private void button_go_Click(object sender, EventArgs e)
        {
            webView2_main.Source = new Uri(textBox_url.Text.Trim());
        }

        private void button_back_Click(object sender, EventArgs e)
        {
            if(webView2_main.CanGoBack) webView2_main.GoBack();
        }

        private void button_forward_Click(object sender, EventArgs e)
        {
            if (webView2_main.CanGoForward) webView2_main.GoForward();
        }

        private void button_test_Click(object sender, EventArgs e)
        {
            var a = new Dictionary<string, object>();
            a["123"] = "xxxyy";
            a["abc"] = 15.23;
            a["0"] = true;
            tool.callJs(a);
        }
    }
}

依赖的object必须实现COM接口:

using Microsoft.Web.WebView2.WinForms;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

// https://learn.microsoft.com/zh-tw/dotnet/api/microsoft.web.webview2.core.corewebview2.addhostobjecttoscript?view=webview2-dotnet-0.9.628-prerelease

namespace webview
{
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class webTool
    {
        private WebView2 web;

        public webTool(ref WebView2 web)
        {
            this.web = web;
        }
        public void msg(string txt)
        {
            MessageBox.Show(txt, "By Form", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
        public void callJs(object args)
        {
            string js = $"console.log({JsonConvert.SerializeObject(args)})";
            web.ExecuteScriptAsync(js);
        }
    }
}

html Demo参考:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS with C# Demo</title>
</head>
<script>
    var tool = window.chrome.webview.hostObjects.tool;
    function call_C(){
    console.log(tool);
    tool.msg("hello, i am from web ui");
    alert("ok");
    }
</script>
<body>
    <button onclick="call_C()">Call C# Code with message</button>
    <pre>
    var tool = window.chrome.webview.hostObjects.tool;
    function call_C(){
        console.log(tool);
        tool.msg("hello, i am from web ui");
        alert("ok");
    }
</pre>
</body>


</html>

程序Setup打包

对于打包程序,使用Visual Studio Setup Installer Project创建,参考:

  • Unistall 提供
  • 手动拖动文件夹可以快速添加
  • 需要手动判断需要的文件
  • Program File一般无写权限,使用AppData/Local/xxx作为自己的程序数据目录

参考文章:

  • https://www.pianshen.com/article/14091375659/
  • https://blog.csdn.net/jk_rou/article/details/130307402
  • https://betheme.net/yidongkaifa/72139.html?action=onClick

Webview2 控件找不到

如果遇到Webview2控件在Toolbox的工具箱中找不到,可以考虑下面2个方案:

  1. 检查webview2的版本依赖,一般有对应Edge版本要求,所以,升级Edge就好了
  2. 当前Webview2安装包没有你使用的net framework/net core版本,但是实际上还是可以用的,参照如下方法,手动添加到工具箱就可以啦。
**Solution**

I found the solution for adding the WebView2 control to the toolbox on the GitHub site you provided, post is [here](https://github.com/MicrosoftEdge/WebViewFeedback/issues/323). Here are the details of the solution for others to follow:

- Right-click on the toolbar in Visual Studios
- Select 'Choose Items...'
- Click the '.NET Framework Components' tab
- Click 'Browse', may have to wait for scan to finish
- Navigate to '<your-solution-folder>\\packages\\Microsoft.Web.WebView2.0.9.538-prerelease\\lib\\net462'
- Select the correct DLL for your application type
- Once the file is selected click the 'OK' button in the window

Done! Now you can access the WebView2 control in the toolbox. If you're using .Net Core then try replacing 'net462' with 'netcoreapp3.0' in the folder path.

注意:

  1. Webview2目前并不是支持所有的net framework!!!
  2. 如果遇上Webview2安装完成后在ToolBox不显示问题,需要检查Edge浏览器版本。还要核对你使用的net framework版本。参考这里:https://www.nuget.org/packages/Microsoft.Web.WebView2#supportedframeworks-body-tab。
  3. 如果你用net 4.8 可以考虑手动添加net 4.5的dll使用,木有问题。但是net core 6/7 使用 3的dll肯定是不行的
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐