You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Windows多版本High DPI缩放及WinForms DPI感知最简实现咨询

我来帮你理清楚这些DPI相关的问题,毕竟WinForms在高DPI下的适配确实容易搞混:

Windows 7、8、8.1及10的High DPI缩放机制

先逐个系统拆解清楚,你就能明白不同版本的核心差异:

Windows 7

  • 只有系统级全局DPI缩放,所有显示器必须共用同一个缩放比例。如果应用未做DPI感知,系统会直接拉伸应用窗口(位图缩放),结果就是界面模糊。
  • 完全不支持单显示器独立DPI设置,更没有每显示器DPI感知的能力。

Windows 8/8.1

  • 首次引入每显示器DPI感知v1,但支持得比较粗糙:
    • 应用可以检测单个显示器的DPI值,但切换到不同DPI的显示器时,需要手动处理界面重绘,系统不会自动调整。
    • 未做DPI感知的应用依然会被系统拉伸模糊,不过新增了DPI虚拟化机制,让旧应用能勉强在高DPI屏幕上运行,但体验一般。

Windows 10(创意者更新前,即1703版本之前)

  • 延续了Win8.1的每显示器v1支持,同时优化了系统缩放算法,但核心机制没太大变化。这里明确回答你:创意者更新之前是支持High DPI的,只是没有后来更完善的特性。
  • 依然依赖应用主动做DPI感知,否则界面还是会模糊。

Windows 10创意者更新(1703及之后)

  • 推出了每显示器DPI感知v2,这是目前最完善的方案:
    • 系统会主动通知应用DPI变化,.NET 4.7+的WinForms原生控件会自动适配缩放,比如控件大小、字体都会自动调整,不用写太多手动代码。
    • 拖拽窗口到不同DPI的显示器时,界面会自动重绘适配,不会再出现模糊或布局错乱的问题。
  • 还新增了系统增强缩放,对未做DPI感知的应用用更智能的算法缩放,模糊感比之前小很多。
VS2017开发WinForms实现跨版本DPI感知的最简方式

你提到的app.config和app.manifest配置确实容易混淆,我整理了一套最简的跨版本配置,覆盖Win7/8/8.1和Win10创意者更新:

首先要确保项目目标框架是**.NET Framework 4.7或更高**,因为WinForms的DPI改进都是从这个版本开始的。

1. 配置app.manifest

在项目中添加或修改app.manifest,加入以下内容声明应用的DPI感知级别:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <!-- 让Win7/8/8.1识别,支持系统DPI和每显示器感知 -->
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true/PM</dpiAware>
    <!-- 优先用Win10 1703+的Per-Monitor v2, fallback到Per-Monitor v1 -->
    <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
  </windowsSettings>
</application>

这个配置能让不同版本的Windows都识别到你的应用是DPI感知的,不会强制启用虚拟化。

2. 配置app.config

在app.config的<runtime>节点下添加这个开关,启用WinForms的DPI适配特性:

<runtime>
  <AppContextSwitchOverrides value="Switch.System.Windows.Forms.EnableHighDpiImprovements=true" />
</runtime>

开启这个后,大部分WinForms原生控件会自动处理DPI缩放,比如按钮、文本框的大小和字体都会跟着DPI调整,省去很多手动代码。

3. 兼容性配置(必加)

就是你提到的<compatibility>配置,用来告诉系统你的应用兼容这些Windows版本,避免系统用兼容模式运行(兼容模式会导致DPI感知失效):

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
  <application>
    <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /> <!-- Windows 7 -->
    <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /> <!-- Windows 8 -->
    <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /> <!-- Windows 8.1 -->
    <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /> <!-- Windows 10 -->
  </application>
</compatibility>

额外小提示

  • 如果你有自定义控件,可能需要手动处理DpiChanged事件,调整控件的大小、字体或者绘制逻辑,但原生控件基本不用管。
  • 测试的时候一定要在不同缩放比例的显示器上验证,比如100%、125%、150%,还要拖拽窗口到不同DPI的显示器,看看界面是否正常。

内容的提问来源于stack exchange,提问作者Chris K

火山引擎 最新活动