我在 C# 中创建了一个简单的 Winforms 应用程序。当我在具有高 DPI 设置(例如 150%)的机器上运行应用程序时,应用程序会按比例放大。到现在为止还挺好!但不是用更大的字体大小渲染字体,所有文本也只是按比例放大。这当然会导致文本非常模糊(在按钮等所有控件上)。
Windows 不应该负责正确呈现文本吗?例如,我的应用程序的标题栏呈现清晰明了。
一旦超过 100%(或勾选“XP 风格 DPI 缩放”复选框的 125%),Windows 默认会接管 UI 的缩放。它通过让您的应用程序将其输出呈现到位图并将该位图绘制到屏幕来实现。该位图的重新缩放使文本不可避免地看起来模糊。一种称为“DPI 虚拟化”的功能,它使旧程序可以在高分辨率显示器上使用。
您必须明确让它知道您可以通过将<dpiAware>
元素添加到清单来处理更高的 DPI 设置。MSDN 页面在这里,但它不完整,因为它省略了 UAC 设置。项目+添加新项目,选择“应用程序清单文件”。编辑清单文本或复制/粘贴:
<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
您还可以在 Main() 方法中调用 SetProcessDPIAware(),例如,如果您使用 ClickOnce 进行部署,则必须这样做:
[STAThread]
static void Main() {
if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); // Edit as needed
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
更新,如果您使用 VS2015 Update 1 或更高版本,这个常见的需求最终会更容易一些。添加的manifest已经有相关指令了,去掉注释即可。
搜索关键字,以便我可以找到此帖子:dpiAware
可以以两种不同的模式开发应用程序。
第一个是声明我们的应用程序是非 DPI 感知的(不声明任何内容将默认为此)。在这种情况下,操作系统将以预期的 96 DPI渲染我们的应用程序,然后执行我们之前讨论的位图缩放。结果将是一个看起来模糊的应用程序,但布局正确。
第二个选项是将应用程序声明为可识别 DPI。在这种情况下,操作系统不会进行任何缩放,而是让您的应用程序根据屏幕的原始 DPI 进行渲染。在 per-monitor-DPI 环境中,您的应用程序将以所有屏幕中最高的 DPI 呈现,然后此位图将按比例缩小到每个显示器的适当大小。缩小比例会比放大比例带来更好的观看体验,但您可能仍会注意到一些模糊性。
如果您想避免这种情况,您必须将您的应用程序声明为可感知每个监视器的 DPI。然后你必须检测你的应用程序何时被拖过不同的显示器并根据当前显示器的 DPI 进行渲染。
声明 DPI 感知是在清单文件中完成的。
参考以下链接 stackoverflow
使用 .NET Framework 4.7 和 Windows 10 Creators Update (1703) 或更高版本,您必须执行以下操作来为您的 Windows 窗体应用程序配置高 DPI 支持:
声明与 Windows 10 的兼容性。
为此,请将以下内容添加到您的manifest
文件中:
<compatibility xmlns="urn:schemas-microsoft.com:compatibility.v1">
<application>
<!-- Windows 10 compatibility -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
app.config
在文件中启用每个显示器的 DPI 感知。
Windows 窗体引入了一个新的System.Windows.Forms.ApplicationConfigurationSection元素,以支持从 .NET Framework 4.7 开始添加的新功能和自定义。要利用支持高 DPI 的新功能,请将以下内容添加到您的应用程序配置文件中。
<System.Windows.Forms.ApplicationConfigurationSection>
<add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>
重要的
在以前版本的 .NET Framework 中,您使用清单来添加高 DPI 支持。不再推荐这种方法,因为它会覆盖 app.config 文件中定义的设置。
调用静态 EnableVisualStyles 方法。
这应该是应用程序入口点中的第一个方法调用。例如:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
这样做的好处是支持动态 DPI 场景,其中用户在启动 Windows 窗体应用程序后更改 DPI 或比例因子。
这些建议都没有对我有用,但是,在我Form.Font = new
从 中删除 ...之后发生了一些事情Form.Design.cs
,表单开始正确重新缩放,如果 Font 在构造函数中定义或根本没有定义,它就可以工作。为什么?其他人可能能够解释,我只能谈论我所做的更改,并花了几分钟时间弄清楚这是我正在处理的表单的根本原因。希望能帮助到你。
至少从 Visual Studio 2017 开始,您只需添加一个清单文件并取消注释此部分:
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>