如何配置应用程序以在具有高 DPI 设置(例如 150%)的机器上正确运行?

Posted

技术标签:

【中文标题】如何配置应用程序以在具有高 DPI 设置(例如 150%)的机器上正确运行?【英文标题】:How to configure an app to run correctly on a machine with a high DPI setting (e.g. 150%)? 【发布时间】:2017-10-07 13:13:53 【问题描述】:

我用 C# 创建了一个简单的 Winforms 应用程序。当我在具有高 DPI 设置(例如 150%)的机器上运行应用程序时,应用程序会按比例放大。到目前为止,一切都很好! 但是,不是用更大的字体大小渲染字体,而是所有文本也只是按比例放大。这当然会导致文本非常模糊(在按钮等所有控件上)。

Windows 不应该负责正确呈现文本吗?例如,我的应用程序的标题栏呈现清晰明了。

【问题讨论】:

【参考方案1】:

使用 .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 或比例因子。

来源:High DPI support in Windows Forms

【讨论】:

【参考方案2】:

至少从 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>

【讨论】:

【参考方案3】:

这些建议都不适合我,但是,在我从 Form.Design.cs 中删除 Form.Font = new ... 后发生了一些事情,表单开始正确重新缩放,如果在构造函数中定义了字体或一点也不。为什么?其他人可能能够解释,我只能谈论我所做的更改,并花了几分钟时间弄清楚这是我正在处理的表格的根本原因。希望对您有所帮助。

【讨论】:

【参考方案4】:

一旦超过 100%(或选中“XP 风格的 DPI 缩放”复选框时超过 125%),Windows 默认会接管 UI 的缩放。它通过让您的应用程序将其输出呈现到位图并将该位图绘制到屏幕来实现。该位图的重新缩放使文本不可避免地看起来模糊。一种称为“DPI 虚拟化”的功能,它可以让旧程序在高分辨率显示器上可用。

您必须明确告诉它您可以通过将&lt;dpiAware&gt; 元素添加到您的清单来处理更高的 DPI 设置。 MSDN 页面 is here 但它不完整,因为它省略了 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();

UPDATE,如果您使用 VS2015 Update 1 或更高版本,这个常见的需求最终会更容易一些。添加的manifest已经有相关指令了,去掉cmets即可。


搜索关键字,以便我可以找到此帖子:dpiAware

【讨论】:

谢谢,您的解决方案运行良好。剩下的唯一问题是所有图像现在都是原始大小。我想我得想办法在我的 GUI 中添加额外的“视网膜”图标...... @HansPassant 我对模糊字体也有同样的问题,应用此解决方案后,我的控件无法缩放并且无法适应。如何让两者都工作? 对于任何调查这种 Win8 疯狂行为的人,SetProcessDPIAware 已被弃用,并且它也不能正常工作(至少在 Win8.1 中不能),导致在不同控件上不可预测的缩放。我强烈建议改用清单方法。 Hmya,Windows 8.1 获得了每个显示器的 DPI。我不知道我需要那个。 如果要使用 ClickOnce 进行部署,则不能在 manifest 中使用 dpiAware 选项,请改用 SetProcessDPIAware()。【参考方案5】:

可以以两种不同的模式开发应用程序。

第一个是声明我们的应用程序是非 DPI 感知的(不声明任何内容将默认为此)。在这种情况下,操作系统将在预期的 96 DPI 下渲染我们的应用程序,然后执行我们之前讨论过的位图缩放。结果将是一个看起来模糊的应用程序,但布局正确。

第二个选项是将应用程序声明为可识别 DPI。在这种情况下,操作系统不会进行任何缩放,而是让您的应用程序根据屏幕的原始 DPI 进行渲染。在 per-monitor-DPI 环境中,您的应用程序将以所有屏幕中最高的 DPI 呈现,然后此位图将按比例缩小到每个显示器的适当大小。缩小比例会比放大比例带来更好的观看体验,但您可能仍会注意到一些模糊性。

如果您想避免这种情况,您必须将您的应用程序声明为可感知每个监视器的 DPI。然后你必须检测你的应用程序何时被拖过不同的显示器,并根据当前显示器的 DPI 进行渲染。

在清单文件中声明 DPI 感知。

参考以下链接 ***

【讨论】:

如果用户有一个 restored 大小的窗口并移动它以使其部分显示在不同的显示器上怎么办?我们是否需要将所有内容渲染两次并将监视器边界用作边界框? winforms 库涵盖了多少?

以上是关于如何配置应用程序以在具有高 DPI 设置(例如 150%)的机器上正确运行?的主要内容,如果未能解决你的问题,请参考以下文章

如何配置应用程序以在具有高 DPI 设置(例如 150%)的机器上正确运行?

exe4j高dpi设置

win10高dpi设置时禁用显示缩放有啥用?

如何在 Windows/Linux 上设置 Java Swing 应用程序的 DPI?

如何强制高 DPI 手机在引导程序中打开 xs 布局

高 DPI Delphi 程序中的 Sisulizer 运行时变化