创建 DPI 感知应用程序

发布于 2024-09-30 02:10:07 字数 132 浏览 2 评论 0原文

我有一个 C# 表单应用程序。当我更改显示器的 DPI 时,所有控件都会移动。 我使用了代码 this.AutoScaleMode = AutoScaleMode.Dpi,但它并没有避免问题。

有人有想法吗?

I have a form application in C#. When I change the monitor's DPI, all the controls move.
I used the code this.AutoScaleMode = AutoScaleMode.Dpi, but it didn't avoid the problem.

Does anyone have an idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

月牙弯弯 2024-10-07 02:10:07

编辑:从 .NET 4.7 开始,Windows 窗体改进了对高 DPI 的支持。 在 learn 上了解更多相关信息。 microsoft.com 不过,它仅适用于 Win 10 Creators Update 及更高版本,因此根据您的用户群,使用它可能尚不可行。


困难,但并非不可能。当然,最好的选择是迁移到 WPF,但这可能不可行。

我花了很多时间来解决这个问题。以下是一些规则/指南,可使其在没有 FlowLayoutPanel 或 TableLayoutPanel 的情况下正常工作:

  • 始终以默认 96 DPI (100%) 编辑/设计您的应用程序。如果您以 120DPI (125% f.ex) 进行设计,当您稍后返回到 96 DPI 进行工作时,情况会变得非常糟糕。
  • 我已经成功使用 AutoScaleMode.Font ,但我还没有尝试过 AutoScaleMode.DPI 。
  • 确保在所有容器(表单、面板、选项卡页、用户控件等)上使用默认字体大小。 8,25 像素。最好不要在 .Designer.cs 文件中为所有容器设置它,以便它使用容器类中的默认字体。
  • 所有容器必须使用相同的AutoScaleMode
  • 确保所有容器在 Designer.cs 文件中设置了以下行:

this.AutoScaleDimensions = new System.Drawing.SizeF (6楼、13楼); // for design in 96 DPI

  • 如果您需要在标签/文本框等上设置不同的字体大小,请为每个控件设置它们,而不是在容器类上设置字体,因为 winforms 使用容器字体设置来缩放其内容,并且让 f.ex 面板的字体大小与其包含的表单的字体大小不同肯定会产生问题。如果表单和表单上的所有容器使用相同的字体大小,它可能会起作用,但我还没有尝试过。
  • 使用另一台计算机或具有更高 DPI 设置的虚拟 Windows 安装(VMware、Virtual PC、VirtualBox)来立即测试您的设计。只需从 DEV 计算机上的 /bin/Debug 文件夹运行已编译的 .exe 文件即可。

我保证,如果您遵循这些准则,即使您使用特定锚点放置了控件并且不使用流程面板,您也会没事。我们以这种方式构建的应用程序部署在数百台具有不同 DPI 设置的计算机上,我们不再有任何抱怨。所有表单/容器/网格/按钮/文本字段等大小都与字体一样正确缩放。图像也可以,但在高 DPI 下它们往往会有点像素化。

编辑:此链接有很多好的信息,特别是如果您选择使用 AutoScaleMode.DPI: 相关 stackoverflow 问题的链接

EDIT: As of .NET 4.7, windows forms has improved support for High DPI. Read more about it on learn.microsoft.com It only works for Win 10 Creators Update and higher though, so it might not be feasible to use this yet depending on your user base.


Difficult, but not impossible. Your best option is to move to WPF of course, but that might not be feasible.

I've spent A LOT of time with this problem. Here are some rules/guidelines to make it work correctly without a FlowLayoutPanel or TableLayoutPanel:

  • Always edit/design your apps in default 96 DPI (100%). If you design in 120DPI (125% f.ex) it will get really bad when you go back to 96 DPI to work with it later.
  • I've used AutoScaleMode.Font with success, I haven't tried AutoScaleMode.DPI much.
  • Make sure you use the default font size on all your containers (forms, panels, tabpage, usercontrols etc). 8,25 px. Preferrably it shouldn't be set in the .Designer.cs file at all for all containers so that it uses the default font from the container class.
  • All containers must use the same AutoScaleMode
  • Make sure all containers have the below line set in the Designer.cs file:

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); // for design in 96 DPI

  • If you need to set different font sizes on labels/textboxes etc. set them per control instead of setting the font on the container class because winforms uses the containers font setting to scale it's contents and having f.ex a panel with a different font size than it's containing form is guaranteed to make problems. It might work if the form and all containers on the form use the same font size, but I haven't tried it.
  • Use another machine or a virtual windows install (VMware, Virtual PC, VirtualBox) with a higher DPI setting to test your design immediatly. Just run the compiled .exe file from the /bin/Debug folder on the DEV machine.

I guarantee that if you follow these guidelines you will be ok, even when you have placed controls with specific anchors and don't use a flowpanel. We have an app built this way deployed on hundreds of machines with different DPI setups and we no longer have any complaints. All forms/containers/grids/buttons/textfield etc sizes are scaled correctly as is the font. Images work too, but they tend to get a little pixellated at high DPI.

EDIT: This link has a lot of good info, especially if you choose to use AutoScaleMode.DPI: link to related stackoverflow question

半世蒼涼 2024-10-07 02:10:07

注意:这不会修复 dpi 更改时控件移动的问题。这只会修复模糊的文本!


如何在高 dpi 设置中修复模糊的 Windows 窗体:

  1. 转到窗体设计器,然后选择您的窗体(通过单击
    其标题栏)
  2. 按 F4 打开“属性”窗口,
  3. 然后找到 AutoScaleMode 属性,
  4. 将其从 字体(默认) 更改为 Dpi

现在,转到 Program.cs(或 Main 方法所在的文件)并将其更改为如下所示:

namespace myApplication
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            // ***this line is added***
            if (Environment.OSVersion.Version.Major >= 6)
                SetProcessDPIAware();

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }

        // ***also dllimport of that function***
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool SetProcessDPIAware();
    }
}

保存并编译。现在你的表格应该看起来又脆了。


来源:
http: //crsouza.com/2015/04/13/how-to-fix-blurry-windows-forms-windows-in-high-dpi-settings/

note: this will not fix the controls moving , when dpi change. this will only fix blurry text!!.


How to fix blurry Windows Forms in high-dpi settings:

  1. Go the the Forms designer, then select your Form (by clicking at
    its title bar)
  2. Press F4 to open the Properties window,
  3. then locate the AutoScaleMode property
  4. Change it from Font (default) to Dpi.

Now, go to Program.cs (or the file where your Main method is located) and change it to look like:

namespace myApplication
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            // ***this line is added***
            if (Environment.OSVersion.Version.Major >= 6)
                SetProcessDPIAware();

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }

        // ***also dllimport of that function***
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool SetProcessDPIAware();
    }
}

Save and compile. Now your form should look crispy again.


source:
http://crsouza.com/2015/04/13/how-to-fix-blurry-windows-forms-windows-in-high-dpi-settings/

后eg是否自 2024-10-07 02:10:07

我终于找到了屏幕方向和 DPI 处理问题的解决方案。
微软已经提供了一份文档对其进行解释,但有一个小缺陷,会完全终止 DPI 处理。
只需按照下面的文档中“为每个方向创建单独的布局代码”下提供的解决方案即可
http://msdn.microsoft.com/en-us/library/ms838174.aspx

然后是重要的部分!
在 Landscape() 和 Portrait() 方法的代码中,在每个方法的最后添加这些行:

this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;

因此,这 2 个方法的代码如下:

protected void Portrait()
{
   this.SuspendLayout();
   this.crawlTime.Location = new System.Drawing.Point(88, 216);
   this.crawlTime.Size = new System.Drawing.Size(136, 16);
   this.crawlTimeLabel.Location = new System.Drawing.Point(10, 216);
   this.crawlTimeLabel.Size = new System.Drawing.Size(64, 16);
   this.crawlStartTime.Location = new System.Drawing.Point(88, 200);
   this.crawlStartTime.Size = new System.Drawing.Size(136, 16);
   this.crawlStartedLabel.Location = new System.Drawing.Point(10, 200);
   this.crawlStartedLabel.Size = new System.Drawing.Size(64, 16);
   this.light1.Location = new System.Drawing.Point(208, 66);
   this.light1.Size = new System.Drawing.Size(16, 16);
   this.light0.Location = new System.Drawing.Point(192, 66);
   this.light0.Size = new System.Drawing.Size(16, 16);
   this.linkCount.Location = new System.Drawing.Point(88, 182);
   this.linkCount.Size = new System.Drawing.Size(136, 16);
   this.linkCountLabel.Location = new System.Drawing.Point(10, 182);
   this.linkCountLabel.Size = new System.Drawing.Size(64, 16);
   this.currentPageBox.Location = new System.Drawing.Point(10, 84);
   this.currentPageBox.Size = new System.Drawing.Size(214, 90);
   this.currentPageLabel.Location = new System.Drawing.Point(10, 68);
   this.currentPageLabel.Size = new System.Drawing.Size(100, 16);
   this.addressLabel.Location = new System.Drawing.Point(10, 4);
   this.addressLabel.Size = new System.Drawing.Size(214, 16);
   this.noProxyCheck.Location = new System.Drawing.Point(10, 48);
   this.noProxyCheck.Size = new System.Drawing.Size(214, 20);
   this.startButton.Location = new System.Drawing.Point(8, 240);
   this.startButton.Size = new System.Drawing.Size(216, 20);
   this.addressBox.Location = new System.Drawing.Point(10, 24);
   this.addressBox.Size = new System.Drawing.Size(214, 22);

   //note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH!
   this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT
   this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;   //IMPORTANT
   this.ResumeLayout(false);
}

protected void Landscape()
{
   this.SuspendLayout();
   this.crawlTime.Location = new System.Drawing.Point(216, 136);
   this.crawlTime.Size = new System.Drawing.Size(96, 16);
   this.crawlTimeLabel.Location = new System.Drawing.Point(160, 136);
   this.crawlTimeLabel.Size = new System.Drawing.Size(48, 16);
   this.crawlStartTime.Location = new System.Drawing.Point(64, 120);
   this.crawlStartTime.Size = new System.Drawing.Size(248, 16);
   this.crawlStartedLabel.Location = new System.Drawing.Point(8, 120);
   this.crawlStartedLabel.Size = new System.Drawing.Size(48, 16);
   this.light1.Location = new System.Drawing.Point(296, 48);
   this.light1.Size = new System.Drawing.Size(16, 16);
   this.light0.Location = new System.Drawing.Point(280, 48);
   this.light0.Size = new System.Drawing.Size(16, 16);
   this.linkCount.Location = new System.Drawing.Point(80, 136);
   this.linkCount.Size = new System.Drawing.Size(72, 16);
   this.linkCountLabel.Location = new System.Drawing.Point(8, 136);
   this.linkCountLabel.Size = new System.Drawing.Size(64, 16);
   this.currentPageBox.Location = new System.Drawing.Point(10, 64);
   this.currentPageBox.Size = new System.Drawing.Size(302, 48);
   this.currentPageLabel.Location = new System.Drawing.Point(10, 48);
   this.currentPageLabel.Size = new System.Drawing.Size(100, 16);
   this.addressLabel.Location = new System.Drawing.Point(10, 4);
   this.addressLabel.Size = new System.Drawing.Size(50, 16);
   this.noProxyCheck.Location = new System.Drawing.Point(168, 16);
   this.noProxyCheck.Size = new System.Drawing.Size(152, 24);
   this.startButton.Location = new System.Drawing.Point(8, 160);
   this.startButton.Size = new System.Drawing.Size(304, 20);
   this.addressBox.Location = new System.Drawing.Point(10, 20);
   this.addressBox.Size = new System.Drawing.Size(150, 22);

   //note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH!
   this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT
   this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;   //IMPORTANT
   this.ResumeLayout(false);
}

对我来说就像魅力一样。

I finally found solution to problem of both Screen Orientation and DPI handling.
Microsoft has already provided a document explaining it but with a little flaw that will kill DPI handling completely.
Just follow solution provided in the document below under "Creating Separate Layout Code for Each Orientation"
http://msdn.microsoft.com/en-us/library/ms838174.aspx

Then IMPORTANT part!
Inside the code for Landscape() and Portrait() methods at the very end of each add these lines:

this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;

So, the code for these 2 methods would be like:

protected void Portrait()
{
   this.SuspendLayout();
   this.crawlTime.Location = new System.Drawing.Point(88, 216);
   this.crawlTime.Size = new System.Drawing.Size(136, 16);
   this.crawlTimeLabel.Location = new System.Drawing.Point(10, 216);
   this.crawlTimeLabel.Size = new System.Drawing.Size(64, 16);
   this.crawlStartTime.Location = new System.Drawing.Point(88, 200);
   this.crawlStartTime.Size = new System.Drawing.Size(136, 16);
   this.crawlStartedLabel.Location = new System.Drawing.Point(10, 200);
   this.crawlStartedLabel.Size = new System.Drawing.Size(64, 16);
   this.light1.Location = new System.Drawing.Point(208, 66);
   this.light1.Size = new System.Drawing.Size(16, 16);
   this.light0.Location = new System.Drawing.Point(192, 66);
   this.light0.Size = new System.Drawing.Size(16, 16);
   this.linkCount.Location = new System.Drawing.Point(88, 182);
   this.linkCount.Size = new System.Drawing.Size(136, 16);
   this.linkCountLabel.Location = new System.Drawing.Point(10, 182);
   this.linkCountLabel.Size = new System.Drawing.Size(64, 16);
   this.currentPageBox.Location = new System.Drawing.Point(10, 84);
   this.currentPageBox.Size = new System.Drawing.Size(214, 90);
   this.currentPageLabel.Location = new System.Drawing.Point(10, 68);
   this.currentPageLabel.Size = new System.Drawing.Size(100, 16);
   this.addressLabel.Location = new System.Drawing.Point(10, 4);
   this.addressLabel.Size = new System.Drawing.Size(214, 16);
   this.noProxyCheck.Location = new System.Drawing.Point(10, 48);
   this.noProxyCheck.Size = new System.Drawing.Size(214, 20);
   this.startButton.Location = new System.Drawing.Point(8, 240);
   this.startButton.Size = new System.Drawing.Size(216, 20);
   this.addressBox.Location = new System.Drawing.Point(10, 24);
   this.addressBox.Size = new System.Drawing.Size(214, 22);

   //note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH!
   this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT
   this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;   //IMPORTANT
   this.ResumeLayout(false);
}

protected void Landscape()
{
   this.SuspendLayout();
   this.crawlTime.Location = new System.Drawing.Point(216, 136);
   this.crawlTime.Size = new System.Drawing.Size(96, 16);
   this.crawlTimeLabel.Location = new System.Drawing.Point(160, 136);
   this.crawlTimeLabel.Size = new System.Drawing.Size(48, 16);
   this.crawlStartTime.Location = new System.Drawing.Point(64, 120);
   this.crawlStartTime.Size = new System.Drawing.Size(248, 16);
   this.crawlStartedLabel.Location = new System.Drawing.Point(8, 120);
   this.crawlStartedLabel.Size = new System.Drawing.Size(48, 16);
   this.light1.Location = new System.Drawing.Point(296, 48);
   this.light1.Size = new System.Drawing.Size(16, 16);
   this.light0.Location = new System.Drawing.Point(280, 48);
   this.light0.Size = new System.Drawing.Size(16, 16);
   this.linkCount.Location = new System.Drawing.Point(80, 136);
   this.linkCount.Size = new System.Drawing.Size(72, 16);
   this.linkCountLabel.Location = new System.Drawing.Point(8, 136);
   this.linkCountLabel.Size = new System.Drawing.Size(64, 16);
   this.currentPageBox.Location = new System.Drawing.Point(10, 64);
   this.currentPageBox.Size = new System.Drawing.Size(302, 48);
   this.currentPageLabel.Location = new System.Drawing.Point(10, 48);
   this.currentPageLabel.Size = new System.Drawing.Size(100, 16);
   this.addressLabel.Location = new System.Drawing.Point(10, 4);
   this.addressLabel.Size = new System.Drawing.Size(50, 16);
   this.noProxyCheck.Location = new System.Drawing.Point(168, 16);
   this.noProxyCheck.Size = new System.Drawing.Size(152, 24);
   this.startButton.Location = new System.Drawing.Point(8, 160);
   this.startButton.Size = new System.Drawing.Size(304, 20);
   this.addressBox.Location = new System.Drawing.Point(10, 20);
   this.addressBox.Size = new System.Drawing.Size(150, 22);

   //note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH!
   this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT
   this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;   //IMPORTANT
   this.ResumeLayout(false);
}

Works like charm for me.

盛夏尉蓝 2024-10-07 02:10:07

看起来这是 Windows 的问题。去掉这两行就解决了一切。

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

这是我得到解决方案的地方:

It looks like this is a problem with Windows. Taking out these two lines fixed everything.

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

This is where I got the solution:

小矜持 2024-10-07 02:10:07

在 Windows 窗体中设计 DPI 感知应用程序确实很困难。您必须使用在 DPI 更改时正确调整大小的布局容器(例如 TableLayoutPanel 或 FlowLayoutPanel)。所有控件也需要调整大小。这些容器的配置可能是一个挑战。

对于简单的应用程序,它可以在合理的时间内完成,但对于大型应用程序,这确实需要大量工作。

It is really hard to design DPI aware applications in Windows Forms. You would have to use layout containers that resize properly when the DPI is changed (such as TableLayoutPanel or FlowLayoutPanel). All controls need resizing as well. The configuration of those containers can be a challenge.

For simple applications it can be done within a reasonable amount of time, but for big applications it is really alot of work.

不忘初心 2024-10-07 02:10:07

根据经验:

  • 不要在 Windows 表单中使用 DPI 感知,除非
  • 对此至关重要,始终将应用程序中的所有表单和用户控件上的 AutoScaleMode 属性设置为 None
  • 结果:所见即所得DPI 设置更改时的界面类型

From experience:

  • don't use DPI awareness with windows forms unless critical
  • to this end always set AutoScaleMode property to None on all forms and user controls in your app
  • The result: WYSIWYG type of interface when DPI settings change
心清如水 2024-10-07 02:10:07

我为此苦苦挣扎了一段时间,最终我找到了一个适用于 Windows 10 和其他潜在系统的超级简单的解决方案。

在您的 WinForms App.config 文件中粘贴以下内容:

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

然后创建一个 app.manifest 文件并在此行中粘贴或注释:

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

完成上述操作后,我能够获得出色的 DPI我的 4k 屏幕上的结果。

查看

I struggled with this for a while eventually I found a super simple solution for windows 10 and potentially other systems.

In your WinForms App.config file paste this:

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

Then create a app.manifest file and paste or comment in this line:

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

After doing the above I was able to get great DPI results on my 4k screens.

Check out this and this for more information.

小嗷兮 2024-10-07 02:10:07
  1. 如果您希望您的 WinForms 应用程序成为 DPI 感知应用程序,除了 Trygve 好的答案之外,如果您有大型项目,您可能希望自动缩放表单及其内容,您可以通过创建 ScaleByDPI 函数来实现此目的: ScaleByDPI

函数将收到通常是一个表单的 Control 参数,然后递归地迭代所有子控件(if (control.HasChildren == true)),并缩放应用程序控件的位置和大小。字体的大小和大小与操作系统配置的 DPI 相关。您也可以尝试对图像、图标和图像实施它。图形。

函数的特别说明:

ScaleByDPI 对于所有具有默认字体大小的控件,您需要将其 Font.Size 设置为 8.25。

b.您可以通过 (control.CreateGraphics().DpiX / 96) 和 (control.CreateGraphics().DpiY / 96) 获取 devicePixelRatioX 和 devicePixelRatioY 值。

c.您将需要缩放 Control.Size & Control.Location 基于control.Dock 和Control.Location 的算法控制.锚值。请注意,control.Dock 可能有 6 个可能值中的 1 个,而 control.Anchor 可能有 16 个可能值中的 1 个。

d.该算法需要为下一个布尔变量 isDoSizeWidth、isDoSizeHeight、isDoLocationX、isDoLocationY、isDoRefactorSizeWidth、isDoRefactorSizeHeight、isDoRefactorLocationX、isDoRefactorLocationY、isDoClacLocationXBasedOnRight、isDoClacLocationYBasedOnBottom 设置值。

e.如果您的项目使用 Microsoft 控件以外的控件库,则该控件可能需要特殊处理。

有关上述 (d.) bool 变量的更多信息:

*有时需要将一组控件(可能是按钮)依次放置在同一垂直线上,并且它们的 Anchor 值包括 Right 而不是 Left,或者需要将它们依次放置在同一水平线上,且它们的 Anchor 值包括 Bottom 而不是 Top,此时需要重新计算控件的 Location 值。

*如果控件包含“Anchor”顶部和“Anchor”底部和/或左侧和底部是的,您需要重新调整控件大小和大小。位置值。

函数的用途:

ScaleByDPI 将下一个命令添加到任何 Form 构造函数的末尾:ScaleByDPI(this);

b.此外,当动态添加任何控件到 Form 时,调用 ScaleByDPI([ControlName])。

  1. 在构造函数结束后动态设置任何控件的 Size 或 Location 时,请创建并使用以下函数之一来获取 Size 或 Location 的缩放值:ScaleByDPI_X \ ScaleByDPI_Y \ ScaleByDPI_Size \ ScaleByDPI_Point

  2. 为了将您的应用程序标记为 DPI- 要将您的应用程序标记为支持 DPI,请将 dpiAware 元素添加到您的应用

  3. 将所有Control.Font的GraphicsUnit设置为System.Drawing.GraphicsUnit.Point

  4. 在所有容器的*.Designer.cs文件中,将AutoScaleMode值设置为System.Windows.Forms.AutoScaleMode.None

  5. 在ComboBox等控件中; TextBox,更改 Control.Size.Height 没有影响。 更改 Control.Font.Size 将修复控件的高度。

  6. 如果窗体StartPosition的值为FormStartPosition.CenterScreen,则需要重新计算窗口的位置。

  1. If you want your WinForms application to be DPI-Aware application, In addition to Trygve good answer, If you have big project you may want to scale your forms and their content automatically, You can do this by creating ScaleByDPI function:

ScaleByDPI function will receive a Control parameter that is usually a form, and than recursively iterate through all sub controls (if (control.HasChildren == true)), and scale location and sizes off your application controls & sizes and sizes of fonts to the OS configured DPI. You can try to implement it also for images, icons & graphics.

Special notes for ScaleByDPI function:

a. For all controls with default Font sizes, you will need to set their Font.Size to 8.25.

b. You can get devicePixelRatioX and devicePixelRatioY values by (control.CreateGraphics().DpiX / 96) and (control.CreateGraphics().DpiY / 96).

c. You will need scale Control.Size & Control.Location by algorithm that based on control.Dock & control.Anchor values. Be noticed that control.Dock may have 1 of 6 possible values and that control.Anchor may have 1 of 16 possible values.

d. this algorithm will need set values to next bool variables isDoSizeWidth, isDoSizeHeight, isDoLocationX, isDoLocationY, isDoRefactorSizeWidth, isDoRefactorSizeHeight, isDoRefactorLocationX, isDoRefactorLocationY, isDoClacLocationXBasedOnRight, isDoClacLocationYBasedOnBottom.

e. If your project uses a control library other then Microsoft controls, this controls may need a special treatment.

More info on above (d.) bool variables:

*Sometimes a group of controls (may be a buttons) need to be placed one after another on same vertical line, and their Anchor value include Right but not Left, or they need to be placed one after another on same horizontal line, and their Anchor value include Bottom but not Top, in this case you need to re-calculate controls Location values.

*In case of controls that Anchor contains Top & Bottom and\or Left & Right, you will need to re-factor controls Size & Location values.

Uses of ScaleByDPI function:

a. Add next command to the end off any Form constructor: ScaleByDPI(this);

b. Also when adding any control dynamically to a Form call to ScaleByDPI([ControlName]).

  1. When you set Size or Location of any control dynamically after constructor ended, create and use one of next functions in order to get the scaled values of Size or Location: ScaleByDPI_X \ ScaleByDPI_Y \ ScaleByDPI_Size \ ScaleByDPI_Point

  2. In order to mark your application as being DPI-aware, add the dpiAware element to your application's assembly manifest.

  3. Set GraphicsUnit of all Control.Font to System.Drawing.GraphicsUnit.Point

  4. In *.Designer.cs files of all containers, set AutoScaleMode value to System.Windows.Forms.AutoScaleMode.None

  5. in controls like ComboBox & TextBox, changing Control.Size.Hieght have no affect. In this case changing Control.Font.Size will fix control's height.

  6. If form StartPosition value is FormStartPosition.CenterScreen, you will need to recalculate the location of the window.

可可 2024-10-07 02:10:07

作为一名使用 4K 显示器的开发人员,我一直在尝试各种解决方案。所有 WPF 窗口都很好,但所有 WinForm 缩放都错误。
它发生在 WPF 中的 WinForms 应用程序上,但也作为独立的 WinForms。 .NET 4.7.2 中的两个应用程序。所以它应该像所有其他答案中所解释的那样工作,但事实并非如此。

这是我的设置
输入图片此处描述

我最终得出的解决方案是

在 app.manifest 文件中使用“unaware”而不是“PerMonitorV2”

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">unaware</dpiAwareness>
    </windowsSettings>
  </application>

I have been trying all kinds of solutions as a developer with a 4K monitor. All WPF windows are fine, but all WinForms scale wrong.
It happens on a WinForms app within WPF, but also as standalone WinForms. Both applications in .NET 4.7.2. so it should work as explained in all other answers, but it doesn't.

This are my settings
enter image description here

The final solution I ended with is using "unaware" instead of "PerMonitorV2"

In the app.manifest file

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">unaware</dpiAwareness>
    </windowsSettings>
  </application>
许你一世情深 2024-10-07 02:10:07
  1. 项目文件添加(yourproject.csproj):

    true;
    
  2. Program.cs 文件(如果存在)

    ApplicationConfiguration.Initialize();
    
  3. 将其释放。删除此行。因为它设置了 bootstrap 的 dpi 首选项,所以将其自定义为项目的首选项。

    Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    应用程序.运行(主窗体);
    
  4. MainForm.cs构造函数add

    this.AutoScaleMode = AutoScaleMode.Dpi;
    
  5. 并从MainForm.designer.cs中删除

    this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    

这些显然适用于 .Net 6 Winform 应用程序。

  1. Project file add (yourproject.csproj):

    <DpiAwarenessPerMonitor>true</DpiAwarenessPerMonitor>
    
  2. Program.cs file if exists

    ApplicationConfiguration.Initialize();
    
  3. Make it free. Remove this line. Because it sets up bootstrap's dpi preferences, custom it to project's preferences.

    Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(MainForm);
    
  4. MainForm.cs constructor function add

    this.AutoScaleMode = AutoScaleMode.Dpi;
    
  5. And remove from MainForm.designer.cs

    this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    

These work for .Net 6 Winform application clearly.

宫墨修音 2024-10-07 02:10:07

由于 Winform 应用程序表单可能包含控件和图像,因此允许系统调整窗口大小并不是一个解决方案,但如果您能够设法为每个 DPI 分辨率创建一个表单,并具有适当缩放的图像...这不是一个好主意,因为随着屏幕尺寸的增大,字体尺寸会减小。

当使用不同的 DPI 分辨率时,系统会强制您的表单重新定义其控件的大小、位置和字体,但不包括图像,解决方案是在运行时加载时更改表单的 DPI,以便一切都恢复到原始大小和位置。

这是可能的解决方案,我已经使用纸牌游戏应用程序对其进行了测试,其中有大约 80 个图像按钮、TabControls 等。

在每个表单 form_Load 事件中,添加以下代码片段:

 Dim dpi As Graphics = Me.CreateGraphics
    选择案例 dpi.DpiX
        案例120
            '-- 如果您的应用程序设计为 120 dpi,则不执行任何操作
        Case Else
    '-- I use 125 AND NOT 120 because 120 is 25% more than 96
            Me.Font = New Font(Me.Font.FontFamily, Me.Font.Size * 125 / dpi.DpiX)
    End Select

此外,在同一台计算机上测试各种分辨率而无需重新启动的快速技巧:

从控制面板更改分辨率。
不要重启!相反,请关闭您的会话并使用同一用户打开一个新会话。

还有另一个警告:如果您在运行时设置控件的大小和位置,那么您应该将相同的 DPI 系数(例如 125 / Dpi.Dpix)应用于新坐标。因此,您最好从 application.startup 事件中设置 DPIFactor 全局变量。

最后但并非最不重要的一点:

请勿在 Visual Studio 中从原始分辨率以外的其他分辨率打开应用程序,否则当您打开每个表单时,您的所有控件都会移动并调整大小,并且无法返回...

希望这会有所帮助,祝您编程愉快。

Since a Winform application form may content controls AND images, allowing the system to resize YOUR window is NOT a solution, but if you could manage to have one form per DPI resolution, with properly scaled images... And that's not a good idea, since as the screen size grow, the font size diminishes.

When using a different DPI resolution the system forces your form to redefine its control's size, location and font, BUT NOT IMAGES, the solution is to change the form's DPI at runtime, when loading, so that everything goes back to original size and location.

This is possible solution, which I've tested it with a card game application where I've gott some 80 image buttons, TabControls etc.

In each form form_Load event, add this code snippet:

  Dim dpi As Graphics = Me.CreateGraphics
    Select Case dpi.DpiX
        Case 120
            '-- Do nothing if your app has been desigbned with 120 dpi
        Case Else
    '-- I use 125 AND NOT 120 because 120 is 25% more than 96
            Me.Font = New Font(Me.Font.FontFamily, Me.Font.Size * 125 / dpi.DpiX)
    End Select

Besides, a quick trick for testing various resolutions on the same computer, without restarting:

From control panel, change the resolution.
Do not restart! Instead close your session and open a new one with same user.

There is another caveat: If you set a control's size and position at runtime, then you should apply the same DPI factor (eg. 125 / Dpi.Dpix) to the new coordinates. So you'd better set up a DPIFactor global variable from application.startup event.

Last but not least:

DO NOT open your application in Visual Studio from another resolution than the original one, or ALL YOUR CONTROLS will move and resize as you open each form, and there is no way back...

Hope this helps, happy programming.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文