WinForms 4K和1080p缩放/高DPI?

Chr*_*s K 8 .net vb.net highdpi visual-studio winforms

所以,这是一个场景:我试图使我的所有表格(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>
Run Code Online (Sandbox Code Playgroud)

这样,除了我可以解决的小锚定问题之外,表格在4K看起来很完美,看起来就像那样但在1080p中有点模糊.这里是4K:4K新老两种方式.

无论如何,所以我抓住它并尝试.NET 4.7中描述的新方法,针对4.7框架并添加以下代码:

到app.config

<System.Windows.Forms.ApplicationConfigurationSection>
   <add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>
Run Code Online (Sandbox Code Playgroud)

到app.manifest

<!-- Windows 10 compatibility -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
Run Code Online (Sandbox Code Playgroud)

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

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

Me.AutoScaleDimensions = New System.Drawing.SizeF(96.0!, 96.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi
Run Code Online (Sandbox Code Playgroud)

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

cat*_*hat 9

就我而言,我使用推荐的设置进程 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>
Run Code Online (Sandbox Code Playgroud)

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

前:

<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
Run Code Online (Sandbox Code Playgroud)

后:

<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
Run Code Online (Sandbox Code Playgroud)


Nol*_*nar 6

我已经成功为我的两个分别针对.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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码就是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));
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 除非使用ClickOnce部署的应用程序,否则使用pinvoke并没有特别的优势。只需在清单中使用`True / PM`即可获得相同的结果。发现比例因子是使用CreateGraphics()的几个很好的理由之一。 (2认同)