前言
WinForms 和 WPF 都支持高 DPI,但是在默认情况下,不是未开启,就是效果不尽人意。例如,默认情况下,WPF 程序在单个高分屏上表现良好,但是如果把窗口拖动到不同的窗口上去,就会变得模糊。
关于不同的 DPI 缩放(感知)类型,请在此查看:https://docs.microsoft.com/zh-cn/windows/desktop/hidpi/high-dpi-desktop-application-development-on-windows
环境
- Windows 10 1809
- .NET Framework 4.7.2
- Visual Studio 2017 15.9.4
所用环境是发文时最新稳定版。条件所限,其他环境请自行测试。
WPF
默认情况下,WPF 只支持单显示器的 DPI 缩放,在移动到缩放比例不同的显示器时,仍使用系统缩放,导致模糊。下面介绍开启Per monitor DPI awareness的方法。
1. 在 app.manifest 中开启 Per monitor DPI awareness
为了支持 Per monitor DPI awareness,需要修改 app.manifest 文件。如果你的项目没有这个文件,请新建应用程序清单文件,名称保持默认的 app.manifest。

找到清单文件中的这一段:
<!-- 指示该应用程序可以感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需
选择加入。选择加入此设置的 Windows 窗体应用程序(目标设定为 .NET Framework 4.6 )还应
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。-->
<!--<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>-->
可以看到提到了 DPI 感知,但其实上面这部分内容已经有点过时。
我们把下半部分替换成:
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</windowsSettings>
</application>
2. 修改 App.config (4.6.2 及以上不需要)
对于 .NET Framework 4.6.2 以下的版本,还需要修改 App.config 文件。下面是未更改的原始文件。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
</startup>
</configuration>
将其更改为
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
</startup>
<runtime>
<AppContextSwitchOverrides value = "Switch.System.Windows.DoNotScaleForDpiChanges=false"/>
</runtime>
</configuration>
请自行比较不同部分。
3. 测试应用
运行程序,在不同缩放比例的显示器之间拖动。
正常情况下,纯 WPF 部分应该完美缩放,其余部分可能无法完美支持。请根据您的应用自行取舍。
更多内部请查看文后的参考资料。
WinForms
WinForms 的设置与 WPF 有所不同,不能按照 WPF 的方式进行设置。
1. 声明与 Windows 10 的兼容性
在 app.manifest 文件中找到下面部分,并按示例取消注释。如果你的项目没有这个文件,请按上面的方法创建。
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
2. 启用每显示器 DPI 感知
修改 App.config,添加下面内容
<System.Windows.Forms.ApplicationConfigurationSection>
<add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>
根据微软给出的文档,
在以前版本的 .NET Framework 中,你可以使用清单来添加高 DPI 支持。 不再建议使用此方法,因为它会替代在 app.config 文件中定义的设置。
3. 测试应用
WinForms 对高 DPI 的支持更差。通过 API 获取到的像素值是与 DPI 相关的。也就是说,同样窗口大小,在不同显示器上会获取到不同的像素值。你必须手动处理。
参考资料
https://github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI
https://docs.microsoft.com/zh-cn/dotnet/framework/winforms/high-dpi-support-in-windows-forms
本文介绍了如何使WinForms和WPF应用支持高DPI,包括在不同显示器之间保持清晰显示。针对WPF,文章详细说明了在应用程序清单文件中启用Per Monitor DPI awareness的步骤,以及对.NET Framework 4.6.2以下版本的额外修改。对于WinForms,文章指导了声明Windows 10兼容性,启用每显示器DPI感知,以及处理与DPI相关的像素值。
1702

被折叠的 条评论
为什么被折叠?



