尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

WinForm界面美化宝典:用开源库打造高端工业软件界面

WinForm界面美化宝典:用开源库打造高端工业软件界面 1. 先给结论丑的不是WinForm是没人认真做这几件事在工业软件这个圈子里待久了你会发现一个很有意思的现象大家一边骂着WinForm做出来的界面太土了一边又拿Delphi时代的审美在做新项目。我见过太多MES、设备监控、数据采集类的上位机软件功能挑不出毛病但界面就是那种灰底白框、控件歪歪扭扭、字体忽大忽小的观感。时间久了这套界面就会反过来拉低产品的信任度——客户看到界面第一眼潜意识里就会觉得这东西不够专业。但说句公道话WinForm本身没有原罪。它诞生于2003年设计目标是快速开发桌面业务工具那时候的主流审美就是XP风格的按钮和灰白窗体。它的默认控件确实老旧但WinForm有一个被严重低估的优势它是一个高度可定制的渲染框架所有控件都是GDI画出来的理论上你能把它画成任何你想要的样子。问题只在于大部分人没有精力从零写一套自绘控件库。所以行业里慢慢沉淀出了一批专门用来救WinForm界面的开源库。它们分成了几个派别有直接改主题换肤的有提供现代风格控件的有专攻数据可视化的还有做工业组态交互的。这篇文章不打算泛泛而谈我会按实际项目中从丑到好看再到好用的改造顺序逐个把这些库讲清楚包括它们适合什么场景、怎么集成、有哪些坑。文章覆盖的内容适合正在维护老WinForm项目的工程师也适合那些被客户逼着把界面做高级点但不想重写技术栈的团队。下面所有这些库我都在真实的上位机项目里跑过有些是生产环境常年跑的有些是测试完就弃掉的——弃掉的原因我也会一并说。2. 主题换肤是第一优先级SunnyUI与AntdUI的取舍逻辑2.1 为什么说换肤是性价比最高的第一步先做个实验把你现在的WinForm项目把窗体的BackColor从Control改成白色把按钮的FlatStyle改成Flat把字体统一成微软雅黑 9pt。你会发现界面已经顺眼了一半。这说明大多数工业软件丑不是丑在布局而是丑在视觉系统不一致按钮有的带边框有的不带字体有宋体有雅黑有系统默认颜色有灰有白有淡蓝整个界面没有统一的设计语言。主题库就是把这套设计语言打包好交给你的东西。你现在不用自己调每个控件的颜色字体拿来即用。SunnyUI和AntdUI是目前国内用得最多的两个免费开源主题库两者思路有相似之处但取舍完全不同。2.2 SunnyUI老牌稳定适合务实的维护型项目SunnyUIGitHub上的开源项目大概从2018年前后开始流行它的特点是一旦用起来几乎不会让你被迫改动业务代码。它把常见的WinForm控件全部重绘了一遍从Button到DataGridView从TextBox到ListBox还包括一个相当好用的UIChart图表控件。我第一个建议是如果你的项目是要长期维护的MES或设备管理软件SunnyUI是默认选项。理由有几点第一它的控件命名是原生的比如SunnyUI.UI.UiButton继承自Control你以前写的btnXxx.Click事件逻辑一行不用改只是把工具箱里拖的控件换掉第二它的主题全局配置是跑在静态类上的切换主题只需调用UIStyles.SetStyleColor()一套配色让整个窗体所有控件同步变化这在项目里非常省心。具体集成流程是这样的在Visual Studio里用NuGet搜索SunnyUI安装到你的WinForm项目。把项目里主窗体的基类从Form改为UIForm如果不想大改也可以在Main函数里手动调用UIStyles.InitTheme(Color.White)然后在每个窗体Load里调用UIStyles.SetStyleColor(style)。工具箱里会自动出现SunnyUI的控件组你可以把原生的Button、Panel替换成UIButton、UIPanel。需要注意UIForm自带阴影边框和圆角如果你的窗体是Borderless无边框模式要关闭UIStyle.DrawShadow否则部分老显卡环境下会有闪烁。一个关键操作SunnyUI的状态栏、进度条、TabControl都做得不错但它的DataGridViewUIDataGridView默认的滚动条是自绘的数据量大到上万行的时候性能略低于原生的DataGridView。所以如果表格要承载高频刷新的大数据我建议这处用原生DataGridView并配合虚拟模式只是把皮肤色调调成和SunnyUI一致即可。2.3 AntdUI更现代的观感值得为它做一点适配AntdUI是近几年风行起来的另一个项目。它借鉴了蚂蚁金服Ant Design的设计语言控件走的是极简扁平风圆角更大、色彩更大胆按钮hover有微交互动画。AntdUI提供的控件同样涵盖常用范围但它有一个很大的特点它的窗体自绘能力和动画效果明显强于SunnyUI尤其是Button、Switch、Input的过渡动画在WinForm里是很罕见的流畅感。我做一个对比表格方便你快速判断对比项SunnyUIAntdUI控件覆盖度非常全工业场景常用都有较全但部分高级控件还在迭代视觉风格商务稳重偏传统桌面软件现代扁平面类似Web后台性能开销较低适合老电脑动画较多最低配置建议双核4G内存主题切换全局静态切换非常方便更细粒度可针对控件单独设置学习成本低和原生控件几乎无差别中需要理解部分属性语义长期维护活跃度稳定作者持续更新更活跃新特性多但偶尔会有Breaking ChangeAntdUI适合的场景是什么如果你是在给设备厂商做演示型的原型系统或者客户明确说界面要比市面上同类产品好看一点那AntdUI的观感优势立刻能体现出来。它的Input、Select、DatePicker这些控件做出来的表单界面几乎有Web后台管理系统的精致度。但要注意AntdUI的更新节奏比较快跨版本升级时少数控件属性可能改名。我的习惯是一旦项目锁定某个版本就只在后续版本中挑bug修复类的更新避免突发的Breaking Change影响已有的窗体布局。3. 表格和图表不是配角工业数据展示的控件选型3.1 不要再让DataGridView丢人了从虚拟模式到自绘美化做过设备监控软件的人都懂界面上最核心的区域往往是一张表格——实时显示温度、压力、速度、状态等参数。WinForm自带的DataGridView功能不弱但默认外观实在寒酸字体锯齿感强滚动条是老式方块行选中的高亮蓝色和整体界面完全不在一个调性上。目前在开源圈里基于DataGridView做美化的首选方案之一是DataGridView美化库ZX.DataGridView它把表格的表头、单元格选中态、行交替色都重新画过但使用上并没有改变DataGridView的既有编程模型。你原来写在CellFormatting事件里的逻辑照旧。另一个方向是针对超大数据量的实时刷新你需要打开DataGridView的VirtualMode。虚拟模式的核心是表格不为所有行创建实体只在你滚动到可见区域时才触发CellValueNeeded事件按行号返回当前需要显示的值。比如你采集卡每秒刷新1000行数据如果直接使用DataSourceUI线程会被频繁的数据更新阻塞界面卡到没法看。而虚拟模式下DataSource根本不用变你只需要维护一个底层缓存数组在CellValueNeeded里取对应下标的数据即可。再加上DoubleBuffered双缓冲先把表格整体画好再一次性渲染到屏幕流畅度会有质的提升。一个我在项目里实际用过的配置dataGridView1.VirtualMode true; dataGridView1.RowCount 100000; // 不实际创建10万行 dataGridView1.CellValueNeeded (s, e) { if (e.RowIndex _dataCache.Count) { e.Value _dataCache[e.RowIndex][e.ColumnIndex]; } }; // 开启双缓冲避免滚动闪烁 typeof(DataGridView).GetProperty(DoubleBuffered, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) .SetValue(dataGridView1, true);这样处理完10万行数据滚动依然很顺。3.2 曲线工业时序数据最不能省的开源库工业软件的界面上没有一条实时曲线就像汽车仪表盘没有指针——数据都在但没有人能一眼看懂趋势。WinForm自带的Chart控件功能虽然不少但交互和颜值一般尤其是缩放、拖动查看历史数据这些操作做起来手感不够好。这里推荐两个库。第一个是LiveCharts2它是老牌LiveCharts的全面重写版支持WinForm动画平滑缩放交互默认开启。它的绘图模型对标的是ECharts可以绘制多条曲线、面积图、柱状图光标移动时自动显示最近点的数据值非常适合作实时趋势窗口。第二个是ScottPlot它更偏向于科学绘图风格渲染速度极快画上几百万个点的数据也不会卡。如果用LiveCharts2在显示高密度数据时感觉帧率不够ScottPlot通常能轻松顶上去。它的交互也做得不错鼠标滚轮缩放、拖拽平移都是开箱即用的。选型逻辑和建议如果曲线数量不大低于8条、数据频率低每秒几条数据用LiveCharts2能得到更好看的界面如果你要处理振动分析、电信号采集这种每秒上万点的波形直接用ScottPlot。二者可以共存曲线区域用ScottPlot仪表盘和统计图用LiveCharts2互不冲突。3.3 仪表盘、状态灯工业HMI感的关键角色很多上位机界面里需要显示运行/停止/故障这种离散状态如果只用文本框加ForeColor变色既不够清晰也不够好看。开源库HslControls是专门为这种场景做的它有汽车仪表盘、圆环进度、状态灯、管道、液位罐、温度计等几十种工业图元全部是自绘的可以通过属性调整颜色和动画效果。我最常用的三个圆环进度条用来显示完成率或容量占比液位罐用来显示液位运行/停止状态灯自带闪烁动画故障时红灯闪烁非常直观。HslControls不是标准的控件属性的写法是直接用代码创建实例设置大小、位置和颜色再把它添加到窗体。如果你是第一次用建议把初始化代码统一放在InitializeUI()方法里不要和界面设计器混在一起。一个经验这些图元本质上是定时的自绘控件如果界面上同时存在几十个CPU占用会明显上升。合理的做法是设置一个全局的刷新频率比如每秒更新两次而不要让它每个图元独立高频刷新。4. 流程图与工艺图让WinForm拥有组态级交互能力4.1 工业软件躲不开的节点连线需求几乎所有工业上位机软件最终都要画一张设备拓扑图、工艺流程图或网络连接示意图。节点用方框/圆形图标代替设备连线表示数据流向或物理链路。这是WinForm原生体系最吃力的一部分用Label和PictureBox摆出来的伪流程图一旦要拖动、缩放、连线代码量会爆炸而且交互非常僵硬。这时你需要的是图形化开放的画布控件。NodeNetwork是一个完全免费开源的WinForm节点编辑器库它把图元节点、连接线、端口交互都封装好了节点可以自由拖动连接线会跟随节点移动自动更新路径还支持缩放画布。它最初是给类似Shader编辑器这种可视化编程工具设计的但用在工业拓扑图上非常合适。使用NodeNetwork时核心是分三层理解第一层是Node代表一个设备或一个工序你可以给Node自定义标题、端口数量第二层是Connection代表两个节点端口之间的关系第三层是NetworkCanvas它是承载所有内容的画布控件。你只需要把数据模型映射到这三个概念上不需要关心画布内部的GDI绘制逻辑。4.2 映射真实设备数据和写一个简单的自定义节点以一个实时显示五台PLC运行状态的监控界面为例。每个PLC是一个节点节点的输入端口接收另一个节点的数据状态输出端口把状态传给中控节点。你需要在节点内部定义一个属性来接收运行/停止/故障信息并把这个信息画成节点上半部分的指示灯颜色。下面是最简化的实现方式public class PlcNode : Node { public PlcNode(string plcName) { this.Name plcName; var input new NodeInput(输入状态); this.Inputs.Add(input); var output new NodeOutput(输出状态); this.Outputs.Add(output); } }然后在UI层的数据定时器里根据采集到的PLC状态更新节点外观foreach (var node in networkCanvas.Nodes) { if (node is PlcNode plc) { plc.Color plcStatus.ContainsKey(plc.Name) ? (plcStatus[plc.Name] 1 ? Color.LimeGreen : Color.Red) : Color.Gray; } }NodeNetwork的缺点是文档较少很多接口需要翻源码才能弄明白。如果你只是画静态的、不需要用户拖拽的流程图可以考虑另一个更轻的库zygote.be Diagrams或直接上Northwoods GoDiagram的免费社区版后者虽然商用需要授权但在个人项目、学习用途上是够用的交互远超前者。4.3 组态软件派实时画面的画布方案组态软件如WinCC、组态王的核心能力是把数据绑定到图元上图元随数据实时刷新。在WinForm里做这件事绕不开一个大名鼎鼎的库——Sharp7 HMI图元自绘方案。严格说Sharp7不是界面库它是西门子PLC的通信库。但它的作用是在后台给界面提供实时数据。你可以在WinForm上放一个PictureBox然后在Paint事件里用GDI画出管道、阀门、液位等图元数据通过Sharp7从PLC寄存器里定时读取再换算成图元的坐标或颜色。举个例子一个液位罐界面液位值存在PLC的DB块里你用Sharp7的DBRead读到byte数组转成float后在Paint里根据实际量程比例计算出液位矩形高度然后FillRectangle画出来。整个过程不依赖任何第三方图元控件所有效果都控制在自己手里。这样做的优点是极致轻量、运行稳定缺点是绘制代码需要自己维护项目越做越大时复杂度会上升。这是我最推荐的工业监控画面方案核心数据通信走稳定库界面层用GDI自绘中间的数据绑定逻辑自己写一个小的状态管理模块。而不是一味地去寻找一个全能的图控件库。5. 布局与交互细节提升真实操作效率但不起眼但致命5.1 别让用户找按钮TabControl与你该用Dock还是Anchor界面美化到了后期你会发现一个问题大多数工业软件的界面丑不是单个控件差而是布局乱。窗体最大化后控件四分五裂有的按钮不知道被拉伸成了什么比例有的Panel把数据表格挤没了用户每次打开软件都得重新适应。WinForm的布局体系里最不被重视的就是Dock和Anchor组合。我的建议是用三分之一的耐心来规划布局树最外层窗体用Dock属性挂一个ToolStrip顶栏、一个StatusStrip状态栏、一个SplitContainer左右分栏。左侧栏用TreeView做设备列表右侧用TabControl放多个监控页。把这种层级定好之后后续所有控件都放进这个容器框架里不会再乱。TabControl本身默认外观也很一般但可以通过OwnerDraw自绘表头来美化把Tabs的DrawMode设为OwnerDrawFixed再在DrawItem事件里自己画背景、边框和文字配合上方主题库的配色整体观感立刻不同。5.2 DPI缩放一个被90%项目忽略的高级感杀手很多WinForm程序在分辨率100%缩放的开发机上很漂亮拷到客户的2K、4K高分屏显示器上字体变得模糊、控件挤成一团。这个问题的根本原因是WinForm默认不是DPI自适应的。好在在.NET 4.7以上版本中官方给了应用级解决方案。在app.config里加上System.Windows.Forms.ApplicationConfigurationSection add keyDpiAwareness valuePerMonitorV2 / add keyEnableWindowsFormsHighDpiAutoResizing valuetrue / /System.Windows.Forms.ApplicationConfigurationSection同时在Program.cs的Main函数里加上Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false);另外桌面上右键属性里的更改高DPI设置——程序兼容性里的替代高DPI缩放行为也要让测试工程师专门测一遍。但即使开启了PerMonitorV2第三方自绘控件也未必完全适配。SunnyUI和AntdUI的绝大多数控件对DPI的适配已经做得很好但如果你用了原生DataGridView 自绘列头仍可能出现像素偏移。我的经验是在开发机就把缩放比设成125%、150%各跑一遍把所有变形的地方记录到一个清单里逐项修。这是WinForm项目上线前最容易被忽略、上线后客户最先骂的事。5.3 输入校验和动画反馈让界面活起来客户感受到的流畅交互很多时候不是性能参数而是操作反馈。比如按钮点击后没有任何状态变化操作者会怀疑自己有没有点到输入框输入了非法数字等提交时才弹一个苦涩的MessageBox体验就很廉价。用AntdUI或SunnyUI之后按钮自带按下和Hover效果输入框自带聚焦边框这种活的感觉就有了。但有些反馈还得自己加比如启动一个耗时的数据导出任务时界面上加一个加载动画操作成功后状态栏绿色闪烁一下参数合法校验失败时对应输入框的边框变成红色并弹出一个自动消失的提示气泡。这些都是很小的代码量但组合起来能让一个老项目看起来脱胎换骨。我个人的经验是不要迷信极简主义工业软件的用户都是要盯8小时屏幕的人适当的颜色反馈、图标提示比什么都重要。6. 混搭改造老项目不重写也能循序渐进口6.1 从哪个窗体开始最稳妥很多团队面临的实际问题是项目已经上线几年代码几万行起步整个窗体替换成新控件库风险极大。这时候我的建议是不要全面推倒做界面混搭即核心业务窗体维持原样把登录窗口、主菜单、状态栏这几个最影响第一印象的窗体优先替换。理由很简单客户对一个软件好不好看的判断90%来自打开软件的前30秒。登录界面、主窗口的菜单和布局、状态栏的颜色决定了第一印象。而具体的参数配置窗体、报表打印窗体哪怕还是老样子用户也大概率感知不到丑因为那里没有对比。所以第一步改造顺序是登录窗 → 主窗体框架菜单栏状态栏背景色 → 数据总览仪表盘第一个Tab页 → 其余Tab页逐步替换。6.2 动态换肤万能的Control遍历法如果你不想把子窗体的控件一个个替换成新的控件类还有个投机但有效的方案写一个静态工具类遍历窗体所有控件统一设置BackColor、ForeColor、Font、FlatStyle。public static void ApplyUIStyle(Control root) { foreach (Control c in root.Controls) { if (c is Button btn) { btn.FlatStyle FlatStyle.Flat; btn.FlatAppearance.BorderSize 0; btn.BackColor Color.FromArgb(52, 152, 219); btn.ForeColor Color.White; btn.Font new Font(微软雅黑, 9F, FontStyle.Regular); } else if (c is TextBox txt) { txt.BorderStyle BorderStyle.FixedSingle; txt.BackColor Color.White; txt.Font new Font(微软雅黑, 9F); } else if (c is Panel pnl) { pnl.BackColor Color.White; } // 递归遍历子控件 ApplyUIStyle(c); } }这个方式虽然不如彻底换主题库精致但它不需要替换任何原生控件业务代码零改动。在只靠它、不引入任何第三方库的情况下就能让整个项目的控件风格统一起来从杂乱无章变成干净整齐。再配合上文的DPI修正已经能应对大部分客户觉得丑的吐槽。6.3 老项目的性能优化UI卡顿是丑的最大根源最后说一个很多人忽略的事实UI的美丑不仅取决于颜色和造型更取决于流畅度。一个界面再漂亮如果打开一个窗口要转圈三秒客户就会觉得它是绣花枕头。WinForm项目卡顿最常见的原因是UI线程被阻塞。检查你项目里所有的事件处理方法——是否在按钮Click里直接同步读取数据库、调用PLC通信、写日志文件这些操作全部应该放到后台线程或异步方法里UI只负责接收结果。具体做法是把耗时操作丢给Task.Run完成后用Control.BeginInvoke回到UI线程更新界面。如果有大量跨线程更新注意在BeginInvoke里做一次如果窗体还没释放就返回的判断避免窗口关闭后回调引发的ObjectDisposedException。另外用自绘控件的项目还要关注GDI对象泄漏每帧绘制时创建的Pen、Brush、Font用完要Dispose否则程序跑一整天GDI对象数量会飙升到Windows阈值然后整个界面黑屏、控件消失。这个坑我亲眼见过几次排查时看到任务管理器里句柄数飙到一万多基本就能定性了。一个简单的自查方法程序运行后打开任务管理器看进程的句柄数是否每隔几分钟就涨几百个。如果是代码里一定有没有释放的GDI对象。7. 写在最后改造的核心不是库是把界面品质当成正经事文章写到这里WinForm界面美化的主要路线都过了一遍。你会发现我并不想说用了XX库就万事大吉因为真正让一个工业软件好看的是背后那个团队是否愿意为界面细节花时间有没有统一的设计规范、有没有专门的UI走查、有没有真实用户反馈的收集机制。开源库只是把重复造轮子的部分省掉了但配色、间距、字体、反馈动画这些仍然需要人为把控。SunnyUI给了你一套控件但决定界面能不能看的是你怎样把这些控件组合起来AntdUI给了你流畅的动画但滥用动画一样会让人觉得花哨廉价。从我自己的项目经验看最有效的工作方式不是找最强的界面库而是确定一套原则第一全局风格统一不允许出现三种以上的按钮样式第二所有窗体遵循同样的边距、字号、颜色规范第三任何新控件引入之前先在Demo窗体里做一轮视觉对比第四性能优化永远排在特效前面先流畅再漂亮。如果你现在正守着老项目发愁我的建议很直接从换主题库开始把登录窗和主框架先做出来拉上同事一起看看效果再逐步铺开。这条路不需要重写代码也足够让产品在一两个迭代周期内脱胎换骨。WinForm给不了你Web前端的无限可能性但那份工业级稳定与可控配合现在这些开源库足以做出一套既不丑、又耐用的界面来。
返回列表