【问题标题】:WinForms 4K and 1080p scaling / high DPI?WinForms 4K 和 1080p 缩放/高 DPI?
【发布时间】:2018-08-07 07:26:36
【问题描述】:

所以,情况如下:我正在尝试使我的所有表单(即 Winforms)在 4K 和 1080p(也称为高 DPI 或“dpi-aware”)中看起来不错。我(出于这个问题的目的)有三种形式: frmCompanyMasterEdit 继承自 frmBaseEdit 继承自 frmBase 继承形式 System.Windows.Forms.Form

我尝试了旧方法,即在清单中让我的应用程序可识别 DPI:

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
  </application>

这样,除了我可以修复的小锚定问题外,表格在 4K 下看起来很完美,看起来就像那样,但在 1080p 下有点模糊。这是 4K:4K both old and new ways

无论如何,所以我从头开始并尝试使用 .NET 4.7 中描述的新方法,针对 4.7 框架并添加以下代码:

到 app.config

<System.Windows.Forms.ApplicationConfigurationSection>
   <add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>

到 app.manifest

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

并将旧代码从 app.manifest 中取出,以免覆盖新的 .NET 4.7 方式。我确保将代码放在适当的位置。 所以这里的表格在 4K 中看起来不错,如上图,但现在在 1080p 中它非常放大,如下所示: 1080p new way

因此,无论哪种方式,除了较小的锚定问题外,表格在 4k 中看起来很棒,而且(旧方式)尺寸合适但在 1080p 中有点模糊,或者在 1080p 中不模糊但确实放大了。 我还必须更改所有 Designer.vb 文件中的这两行,如下所示:

Me.AutoScaleDimensions = New System.Drawing.SizeF(96.0!, 96.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi

我不知道为什么我无法让它在 1080p 中看起来合适。就像我说的,我的目标是 4.7 .NET 框架。我在适当版本的 Windows 10(版本 1709 / Creator's edition)上运行。 1080p 以 100% 缩放。此外,我们没有资源升级到 WPF。

【问题讨论】:

标签: .net vb.net winforms visual-studio highdpi


【解决方案1】:

我已成功为我的两个分别针对 .NET 4.5 和 4.7 的 Winforms 应用程序添加了 DPI 支持。

过去,我尝试通过清单文件添加支持,但没有成功。幸运的是,我找到了以下解决方案:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WinformsApp
{
    static class Program
    {
        [DllImport("Shcore.dll")]
        static extern int SetProcessDpiAwareness(int PROCESS_DPI_AWARENESS);

        // According to https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx
        private enum DpiAwareness
        {
            None = 0,
            SystemAware = 1,
            PerMonitorAware = 2
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            SetProcessDpiAwareness((int)DpiAwareness.PerMonitorAware);

            Application.Run(new MainForm());
        }
    }
}

上面的代码就是您的 Program.cs 文件的样子。当然,您必须将它移植到 VB,但应该很容易做到。

这在 Windows 10 中完美运行,无需任何其他修改。

在两个 Winforms 应用程序之一中,我使用像素坐标通过 Graphics 类呈现字符串,这导致我的字符串发生偏移。修复非常简单:

private void DrawString(Graphics g, string text, int x, int y)
{
    using (var font = new Font("Arial", 12))
    using (var brush = new SolidBrush(Color.White))
        g.DrawString(text, font, brush, LogicalToDeviceUnits(x), LogicalToDeviceUnits(y));
}

基本上,我必须使用Control.LogicalToDeviceUnits(int value) 来缩放像素坐标。

除此之外,我根本不需要接触我的代码。

【讨论】:

  • 除非这是一个 ClickOnce 部署的应用程序,否则使用 pinvoke 没有特别的优势。只需在清单中使用 True/PM 即可获得相同的结果。发现比例因子是使用 CreateGraphics() 的少数充分理由之一。
  • 谢谢,我会检查的。但是我的应用程序没有Main() 方法,而是有一个启动表单。我在想我应该把上述代码放在启动表单的构造函数中还是在它的加载事件中?
  • @ChrisK。我测试了它,它也可以在构造函数中工作。
  • 谢谢,我试试看。但是@HansPassant 不是旧方法(每监视器 V1)吗? Microsoft 将 per monitor version 2 添加到 .NET Framework 4.7,您可以在 app.config 中添加它。
  • @HansPassant。经过一番调查,我终于发现了为什么我使用 P/Invoke 而不是清单。我的应用是屏幕保护程序,并且清单仅在调试期间有效,但在作为屏幕保护程序启动时无效。
【解决方案2】:

在我的情况下,我在设置过程 DPI 感知的推荐方法中遇到了太多故障:最小表单大小无法正常工作,在具有不同 DPI 的显示器之间移动表单时随机混乱,无明显原因裁剪表单,Segoe UI 字体无法正确缩放,拆分器容器中的锚定控件会使所有内容浮动在错误的位置等。

还有一个问题是图标变小了,您需要更新代码以选择性地为按钮、ListView、TreeView 等加载更高分辨率的版本。

我最终使用的替代方法是使用 Windows 10 的设置通过“GDI 缩放”覆盖缩放行为。这可以在应用的清单中声明。

设置如下,你可以先试试看是否满足你的需求:

可以通过修改项目中的 app.manifest 文件并添加以下条目来自动设置此设置:

<asmv3:application>
  <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">
    <gdiScaling>true</gdiScaling>
  </asmv3:windowsSettings>
</asmv3:application>

代码可能会给您一个“asmv3”无法识别的错误。要添加 asmv3 命名空间,请修改您的 app.manifest 以包含它:

之前:

<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">

之后:

<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    • 2020-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多