WinForm 上位机最烦的事之一,就是在厂里 1366×768 的小屏看着正好,搬到另一台 1920×1080 或 250% 缩放的工控机上,控件重叠、字体发虚、按钮被挤掉半截。根治的路线就一条主线:让布局跟着比例走、字体跟着缩放走,而不是跟着"绝对像素"走。宁波这个产线项目我们踩遍了坑,把全过程整理成可直接照做的诊断步骤和三样核心做法。
先搞明白:分辨率为什么会把界面"挤坏"?
WinForm 默认走"逻辑坐标 + AutoScale"机制。一旦系统把 DPI 从 100%(96DPI)调到 125%/150%(120/144DPI),控件字体会变大而像素不跟着变,如果代码里固定了某个控件的 Size 或 Location,缩放后就会错位、被截断。另一条常见病因是设计时用绝对坐标把控件一个个定死,到不同 DPI/分辨率下就原形毕露。先把"逻辑坐标"和"物理像素"的关系理顺,才是正路。
对策一:先把 DPI 感知声明对,止住"字体发虚"
第一件事是把上位机声明成 Per-Monitor DPI Aware,否则 Windows 会替窗体做位图缩放,导致字虚。两种做法:项目加 manifest 声明 dpiAware;或代码调 SetProcessDpiAwareness,.NET 4.7+ 可用 PerMonitorV2。声明到位、窗体按实际 DPI 重算后,模糊问题先消一半。
| 做法 | 写法 / 配置 | 说明 |
|---|---|---|
| manifest | dpiAware="true" | 最简,脚本部署也方便 |
| PerMonitorV2 | app.manifest 配 dpiAwareness PerMonitorV2 | .NET 4.7+/Win10+,多屏不同缩放能正确切 DPI |
| 代码兜底 | ApplicationHighDpiMode / SetProcessDpiAwareness | 老运行时不得已才用 |
对策二:布局从"绝对坐标"换成"相对摆",止住"控件错位"
把窗体拆成"行列网格":用 TableLayoutPanel 划分区域(百分比列宽行高),内部控件用 Dock 填满或 Anchor 相对边距贴边。这样窗体拉伸或 DPI 变化时,区域等比缩放,控件跟着走。表格列行设成百分比(50%/50%、33%/34%/33%),比"固定 400px"抗缩放强得多。
- 每个 Panel 设 AutoScaleMode=Font,让字号驱动面板尺寸
- 按钮、输入框用 Dock=Fill 填进 TableLayout 单元格
- 避免在固定 Size 的容器里叠 Canvas 式绝对定位
对策三:定一个基准分辨率,字串公式跟着比例走
在布局难以全部相对化、或要同时兼容"1366 触摸屏"和"1080 大屏"的老项目里,我们给窗体定义一个设计基准宽度(比如 1280),运行时取 ScreenWidth / 1280 得到缩放系数,把字体字号和关键间距按系数放大。字体用 ScaleFont = BaseSize * scale,配合 96→120DPI 换算,保证字号等比拉大而不是被系统拉伸糊掉。
窗口本身限制最小 800×600,超高缩放时自动取可用区 90% 不溢出;外层套可滚动容器,真溢出还能滚着操作,不致命。
多屏适配:挂了三块屏,DPI 还不一样怎么办?
宁波那个工位的主机挂了至少三类屏:一块 1366 操作屏、一块 1080 实时看板、一块 1920 数据大屏。真正的难点是各屏 DPI 不同——传统单 DPI 处理会对副屏发虚。根治靠 PerMonitorV2 运行时:给每个 Form 走 Screen.AllScreens 定位目标屏中心,窗体声明自己的 AutoScale,再统一丢到目标屏。配合 PerMonitorV2 后,三屏文字都锐利、控件不错位。
照看的落地顺序,从零改怎么走?
- 加 manifest 开 Per-Monitor V2,先让字体不发虚(.NET 4.7+ 或 Core)
- 把最外层容器换成 TableLayoutPanel + 百分比行列,这是治错位的根
- 控件绝对定位 Location 全部改成 Anchor/Dock,只留必要的最小 Size
- 字体改成"基准字号 × 缩放系数",不写死某个固定字号
- 多屏时每个 Form 指定 Screen + DPI,用 Screen.AllScreens 定位
- 跑核心四种分辨率截图回归,每改一处重拍一遍
你的上位机是不是也"看着没事,一换屏就鬼畜"?
行动建议:今天就拿你的 WinForm 上位机,在三台不同分辨率/缩放的机器上各截一张图,对照本页三对策,先把 DPI 感知和相对布局这两件修到位——这两件到位,八成错位就没了。真遇到 250% 缩放的极端工控机,再上基准缩放兜底。分辨率适配没有银弹,但顺着"认 DPI → 相对布局 → 基准缩放"这条路,是能一路修完的。
