前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于WinForms的跨显示器DPI自适应

关于WinForms的跨显示器DPI自适应

作者头像
Edi Wang
发布2019-07-24 16:52:07
2.5K0
发布2019-07-24 16:52:07
举报
文章被收录于专栏:汪宇杰博客

导语

WinForms 是运行在Windows上的传统.NET桌面应用技术框架。由于历史原因,它对高DPI以及跨不同DPI屏幕的支持有些问题,本文将探索尽可能的解决方案。

Windows 的“黑历史”

Windows 系统的默认DPI(更确切的说法叫 PPI)是96。PPI 的意思是 Pixels per inch,也就是每英寸屏幕显示多少像素的意思。这个值越高,表示屏幕的显示能力越细腻。

但也意味着,要显示物理尺寸和低PPI屏幕相同的画面,高PPI屏幕需要更多的像素来填充。对于一张非矢量图来说,这个问题不好解决,由于向高像素拉伸,这个图片会被“拉模糊”。类似的问题也发生在Windows中,特别是老程序,设计的时候只考虑了96 PPI。而这个历史原因可以在微软的这篇博客里找到详解:

https://blogs.msdn.microsoft.com/fontblog/2005/11/08/where-does-96-dpi-come-from-in-windows/

例:在150% DPI的屏幕上,Windows管理控制台(MMC)均会发生模糊。(可能在微信或网页里不明显)

而在100% DPI 的屏幕上,图像是清晰的。

努力的 Windows 10

由于现在的电脑高分屏(HDPI)越来越多,Windows 10 每半年一次的 Feature Update 一直在努力解决 DPI 的问题。我们可以通过下图的设置搭配,解决很多老程序的DPI适配。但是很难做到跨屏幕DPI自适应。

所谓跨屏幕DPI自适应(Per Monitor-DPI aware),意思就是当你的电脑有外接屏幕时,Windows会选择适配该屏幕的DPI来显示外接屏幕的图像。这个DPI很可能和你电脑的主屏幕是不一样的。例如,用 Surface Pro 外接一个 1920x1080 的22寸显示器,那么Surface的主屏幕通常是 150%以上DPI,而外接显示器是100%。

如果程序自己不支持 Per Monitor-DPI aware,那么你用Windows自带的兼容模式调整完,会发现虽然两个屏幕都是清晰的图像,但是应用界面在低DPI屏幕上会被放大。并不完美。所以最地道的解决方式,是开发支持 Per Monitor-DPI aware 的程序。

微软自己的应用也有这方面的改进。例如 Visual Studio 2019 开始已经天然支持 Per Monitor-DPI aware。(要求 Windows 10 v1803及.NET Framework 4.8)

WinForms 能抢救吗

Windows桌面开发最native的三种技术分别是:WinForms、WPF、UWP。因为UWP诞生于现代,所以天生没有DPI适配问题。而WPF的XAML界面也可以轻松适配DPI。唯独 WinForms 历史包袱太重,不改是不行的。我们来试试能否抢救。

首先,我在VS2019中使用150% DPI的主屏幕,设计器视图不模糊,但按钮尺寸有问题,控件位置如下:

留意红色箭头位置。在VS里一切正常。然而运行起来,在150% DPI的主屏幕是会模糊,并且控件错位。

将窗口拖动到100% DPI的屏幕上,UI不模糊,但控件依旧错位。

按照微软官网文档 https://docs.microsoft.com/en-us/dotnet/framework/winforms/high-dpi-support-in-windows-forms 的描述,.NET Framework 从4.7开始,改善WinForms的DPI支持。因此第一步,我将该程序的运行时改为4.7.2(Windows 10 1803以上版本自带)

在应用根目录加入一个 app.manifest 文件。

取消注释其中的 assembly/compatibility/application 下的Windows 10 GUID。

<!-- Windows 10 -->

<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />

然后在 App.config 底下加入:

<System.Windows.Forms.ApplicationConfigurationSection>

<add key="DpiAwareness" value="PerMonitorV2" />

</System.Windows.Forms.ApplicationConfigurationSection>

现在发现控件位置在150% DPI的主屏幕上正确显示,整个UI不模糊。

但是在 100% DPI 的屏幕上,虽然UI不模糊,但是控件位置依然不正确,并且TextBox变的巨大无比。

微软文档里没提别的方法。但是我发现将运行时改成.NET Framework 4.8 可以修复这个TextBox的爆,但是控件位置依然不正确。

经过仔细观察,发生问题的并不是 TextBox、Label、Checkbox 这几个控件,而是 MonthCalendar 在100% DPI的屏幕上比 150% 的主屏宽。并且 Panel、TableLayoutPanel和Dock的组合拳都没法办法解决这个问题。

.NET Core 3.0 能解决吗?

.NET Core 3.0 目前还在preview 6阶段。从我实验的结果来看,它的DPI适配不需要App.config,而是在Program.cs里加入:

Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);

但最终效果和以上的.NET Framework 4.8的效果是一样的,虽然跨DPI屏幕界面不会模糊,但是 MonthCalendar 的宽度问题依旧。

结论

在 Windows 10 v1903 上(其他版本我没试过),通过 .NET Framework 4.8 + app.manifest + app.config 的配置,可以一定程度上让 WinForms 具有 Per Monitor-DPI aware 的能力,但是部分控件的尺寸还是会不一样,因此发布程序之前需要仔细测试,保证UI可用性,再向用户提供跨屏幕DPI自适应支持。

我的样例程序代码:https://github.com/EdiWang/DotNet-Samples/tree/master/WinForms-DPI-PMA/PerMonitorAwareDPIForms

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 汪宇杰博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档