做 .NET 桌面开发的人,大概都绕不开 WinForm。WinForm 好上手,生态成熟,但 UI 这东西……做出来总有一股上世纪的气息。你可以用 GDI+ 慢慢画,可以用第三方控件包装点门面,但想做一个现代化的登录界面、一个带渐变和动画的设置面板,WinForm 原生能做到的事情极为有限。
于是很多人转投 WPF,WPF 的绑定系统和样式系统确实强大,但 XAML 写复杂 UI 同样费劲,而且学习曲线不低。
那有没有一种方案,能让我用 HTML、CSS、JavaScript 写 WinForm 的界面,同时用 C# 写业务逻辑?
有。这个项目叫 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 吗?
阅读原文:原文链接
该文章在 2026/4/17 16:22:37 编辑过