×

WinForm 界面丑?用 HTML 和 CSS 重塑你的桌面应用

独孤求败 独孤求败 发表于2026-04-17 14:31:49 浏览6 评论0

抢沙发发表评论

做 .NET 桌面开发的人,大概都绕不开 WinForm。

WinForm 好上手,生态成熟,但 UI 这东西……做出来总有一股上世纪的气息。你可以用 GDI+ 慢慢画,可以用第三方控件包装点门面,但想做一个现代化的登录界面、一个带渐变和动画的设置面板,WinForm 原生能做到的事情极为有限。

于是很多人转投 WPF,WPF 的绑定系统和样式系统确实强大,但 XAML 写复杂 UI 同样费劲,而且学习曲线不低。

那有没有一种方案,能让我用 HTML、CSS、JavaScript 写 WinForm 的界面,同时用 C# 写业务逻辑

有。这个项目叫 NanUI


https://github.com/XuanchenLin/NanUI
图片

它是什么

NanUI 是一个基于 .NET 平台的开源框架,核心理念是:用 Web 技术做 WinForm 的 UI

具体来说,它在 WinForm 内部嵌入了一个 Chromium 浏览器内核(基于 CEF,即 Chromium Embedded Framework),你的界面用 HTML5、CSS3、JavaScript 来写,业务逻辑用 C# 来写,两者之间通过一套完善的映射机制互通。

这意味着:任何现代 Web UI 技术——Flex 布局、CSS 动画、SVG 图标、响应式设计——全部可以无差别地跑在你的 WinForm 应用程序里。

背景透明?做。毛玻璃效果?做。渐变色标题栏?做。这些在 WinForm 原生几乎不可能做到的事情,NanUI 让你用几行 CSS 搞定。

图片

快速上手

装两个 NuGet 包:

PM> Install-Package NetDimension.NanUI
PM> Install-Package NetDimension.NanUI.Runtime

修改 Program.cs

using NetDimension.NanUI;

var builder = NanUIApp.CreateBuilder();

var app = builder
    .UseNanUIApp<MyApp>()
    .UseEmbeddedBrowser()  // 启用内置浏览器
    .Build();

app.Run();

创建一个启动类:

classMyAPP : AppStartup
{
protectedoverride MainWindowCreationAction? UseMainWindow(MainWindowOptions opts)
    {
return opts.UseMainFormium<MyWindow>();
    }

protectedoverridevoidProgramMain(string[] args)
    {
        ApplicationConfiguration.Initialize();
    }

protectedoverridevoidConfigureServices(IServiceCollection services)
    {
// 注册嵌入资源
        services.AddEmbeddedFileResource(new EmbeddedFileResourceOptions
        {
            Scheme = "http",
            DomainName = "embedded.app.local",
            ResourceAssembly = typeof(Program).Assembly,
            EmbeddedResourceDirectoryName = "wwwroot",
        });
    }
}

创建一个窗口类,指定 HTML 界面文件:

classMyWindow : Formium
{
publicMyWindow()
    {
// 通过资源域名加载嵌入的 HTML 文件
        Url = new Uri("http://embedded.app.local/index.html");
    }

protectedoverride FormStyle ConfigureWindowStyle(WindowStyleBuilder builder)
    {
var style = builder.UseSystemForm();
        style.TitleBar = false;  // 移除系统标题栏
return style;
    }
}

三分钟,一个用 HTML 和 CSS 写界面的 WinForm 应用就跑起来了。

图片

WinForm 和 JavaScript 之间怎么通信

这是很多人关心的核心问题:我的 C# 代码怎么调 HTML 里的内容?HTML 里的按钮点击怎么触发 C# 的逻辑?

NanUI 提供了一套完整的双向映射机制,分消息通信和对象映射两套体系。

方式一:消息和请求机制

前端通过 formium 对象与后端通信:

// 发送异步请求(带返回值),后端通过 RegisterJavaScriptRequestHandler 处理
const result = await formium.sendHostWindowRequestAsync("save"JSON.stringify(data));

// 发送消息(无返回值),后端通过 RegisterJavaScriptMessagHandler 处理
formium.postMessage("log""用户点击了按钮");

后端在窗口中注册处理器:

// 同步请求处理器
RegisterJavaScriptRequestHandler("save"args => {
    SaveData(args.GetString());
return"保存成功";
});

// 异步请求处理器
RegisterJavaScriptRequestHandler("load"async (args, promise) => {
var data = await LoadDataAsync();
    promise.Resolve(data);
});

// 无返回值消息处理器
RegisterJavaScriptMessagHandler("log"args => {
    Console.WriteLine(args.GetString());
});

方式二:JavaScript Window Binding Object

定义一个继承自 JavaScriptWindowBindingObject 的 C# 类,通过依赖注入注册:

internalclassBackendObject : JavaScriptWindowBindingObject
{
publicoverridestring Name => "backend";

publicoverridestring JavaScriptWindowBindingCode => """
        var backend = {
            getData: function() {
                native function getData();
                return getData();
            }
        };
        """
;

public JavaScriptValue? GetData(Formium sender, JavaScriptArray args)
    {
return JavaScriptValue.CreateString(GetCurrentData());
    }
}

在 AppStartup 中注册到服务:

services.AddWindowBindingObject<BackendObject>();

前端直接通过对象名调用 C# 方法:

const data = await backend.getData();

从 C# 调用 JavaScript

// 执行任意 JS 并获取返回值
var result = await EvaluateJavaScriptAsync<int>("10 + 20");

这套双向通信机制是 NanUI 的核心能力——它是专门为 WinForm 场景设计的,API 简洁,不需要手动处理序列化。

窗口样式:你想怎么做都行

传统 WinForm 的窗口样式受系统限制,做不了太多定制。NanUI 彻底放开了这个限制。

无标题栏窗口:自己画标题栏,自己处理拖动、最小化、最大化、关闭按钮的位置和样式。

Windows 11 云母(Mica)效果

var style = builder.UseSystemForm();
style.TitleBar = false;
style.BackdropType = SystemFormBackdropType.Mica;  // 支持 Mica、MicaAlt、Acrylic、Surface、Transparent 等

NanUI 支持的窗口背景效果包括:Mica(Windows 11 云母)、MicaAlt(深色变体)、Acrylic(亚克力毛玻璃)、Surface(实体)、Transparent(透明)以及 None(无特效)。

离屏渲染:内容渲染在独立图层上,与系统窗口解耦,可实现更复杂的光晕和阴影效果。

所有这些效果,在文档里都有示例代码,照着改就能用。

资源加载:嵌入式、本地文件、数据资源全都支持

NanUI 不强制你把 HTML 文件打包到程序里。它支持三种资源加载方式:

嵌入式资源:把 HTML/CSS/JS 文件作为嵌入资源编译到程序集里,发布时一个 EXE 走天下,适合正式发布。

services.AddEmbeddedFileResource(new EmbeddedFileResourceOptions
{
    Scheme = "http",
    DomainName = "embedded.app.local",
    ResourceAssembly = typeof(Program).Assembly,
    EmbeddedResourceDirectoryName = "wwwroot",
});

本地文件:指定本地文件夹路径,适合开发阶段快速迭代,改 HTML 不需要重新编译。

services.AddLocalFileResource(new LocalFileResourceOptions
{
    Scheme = "http",
    DomainName = "files.app.local",
    PhysicalFilePath = Path.Combine(AppContext.BaseDirectory, "wwwroot"),
});

数据资源:通过 C# 回调动态生成返回内容,适合需要程序化生成页面的场景。

services.AddDataResource("http""data.app.local", provider => {
    provider.ImportFromCurrentAssembly();
});

三种模式可以共存,互不冲突。

图片

轻量替代方案:WinFormedge

CEF 内核功能强大,但代价是包体积大。压缩后大约 125MB。

如果你在 Windows 10/11 环境下开发,并且不需要 CEF 的完整功能,可以看看作者推荐的另一个项目:WinFormedge

它基于微软的 WebView2 作为渲染内核,打包后压缩体积仅 36MB,比 NanUI 轻了将近三分之二。

当然,代价是 WinFormedge 只支持 Windows 10 及以上,不能像 NanUI 那样兼容 Windows 7。

结语

NanUI 解决的是一个很具体的问题:WinForm 开发者想要现代 UI,但不想换技术栈

它没有让你抛弃 C#、抛弃 WinForm 的生态,而是把 Chromium 的渲染能力引入进来,让你能用 Web 技术解决 UI 问题。

技术栈不需要大换血,就能做出让人眼前一亮的界面——这件事本身,就值得一试。

你的下一个 WinForm 项目,打算试试 NanUI 吗?


你在桌面应用开发中遇到的最大 UI 问题是什么?是用什么方案解决的?评论区聊聊。


群贤毕至

访客