创建 DPI 感知应用程序
我有一个 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
编辑:从 .NET 4.7 开始,Windows 窗体改进了对高 DPI 的支持。 在 learn 上了解更多相关信息。 microsoft.com 不过,它仅适用于 Win 10 Creators Update 及更高版本,因此根据您的用户群,使用它可能尚不可行。
困难,但并非不可能。当然,最好的选择是迁移到 WPF,但这可能不可行。
我花了很多时间来解决这个问题。以下是一些规则/指南,可使其在没有 FlowLayoutPanel 或 TableLayoutPanel 的情况下正常工作:
this.AutoScaleDimensions = new System.Drawing.SizeF (6楼、13楼); // for design in 96 DPI
我保证,如果您遵循这些准则,即使您使用特定锚点放置了控件并且不使用流程面板,您也会没事。我们以这种方式构建的应用程序部署在数百台具有不同 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:
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); // for design in 96 DPI
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
注意:这不会修复 dpi 更改时控件移动的问题。这只会修复模糊的文本!
如何在高 dpi 设置中修复模糊的 Windows 窗体:
其标题栏)
现在,转到 Program.cs(或 Main 方法所在的文件)并将其更改为如下所示:
保存并编译。现在你的表格应该看起来又脆了。
来源:
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:
its title bar)
Now, go to Program.cs (or the file where your Main method is located) and change it to look like:
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/
我终于找到了屏幕方向和 DPI 处理问题的解决方案。
微软已经提供了一份文档对其进行解释,但有一个小缺陷,会完全终止 DPI 处理。
只需按照下面的文档中“为每个方向创建单独的布局代码”下提供的解决方案即可
http://msdn.microsoft.com/en-us/library/ms838174.aspx
然后是重要的部分!
在 Landscape() 和 Portrait() 方法的代码中,在每个方法的最后添加这些行:
因此,这 2 个方法的代码如下:
对我来说就像魅力一样。
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:
So, the code for these 2 methods would be like:
Works like charm for me.
看起来这是 Windows 的问题。去掉这两行就解决了一切。
这是我得到解决方案的地方:
It looks like this is a problem with Windows. Taking out these two lines fixed everything.
This is where I got the solution:
在 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.
根据经验:
AutoScaleMode
属性设置为None
From experience:
AutoScaleMode
property toNone
on all forms and user controls in your app我为此苦苦挣扎了一段时间,最终我找到了一个适用于 Windows 10 和其他潜在系统的超级简单的解决方案。
在您的 WinForms
App.config
文件中粘贴以下内容:然后创建一个
app.manifest
文件并在此行中粘贴或注释:完成上述操作后,我能够获得出色的 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:Then create a
app.manifest
file and paste or comment in this line:After doing the above I was able to get great DPI results on my 4k screens.
Check out this and this for more information.
函数将收到通常是一个表单的 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])。
为了将您的应用程序标记为 DPI- 要将您的应用程序标记为支持 DPI,请将 dpiAware 元素添加到您的应用
将所有Control.Font的GraphicsUnit设置为System.Drawing.GraphicsUnit.Point
在所有容器的*.Designer.cs文件中,将AutoScaleMode值设置为System.Windows.Forms.AutoScaleMode.None
在ComboBox等控件中; TextBox,更改 Control.Size.Height 没有影响。 更改 Control.Font.Size 将修复控件的高度。
如果窗体StartPosition的值为FormStartPosition.CenterScreen,则需要重新计算窗口的位置。
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]).
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
In order to mark your application as being DPI-aware, add the dpiAware element to your application's assembly manifest.
Set GraphicsUnit of all Control.Font to System.Drawing.GraphicsUnit.Point
In *.Designer.cs files of all containers, set AutoScaleMode value to System.Windows.Forms.AutoScaleMode.None
in controls like ComboBox & TextBox, changing Control.Size.Hieght have no affect. In this case changing Control.Font.Size will fix control's height.
If form StartPosition value is FormStartPosition.CenterScreen, you will need to recalculate the location of the window.
作为一名使用 4K 显示器的开发人员,我一直在尝试各种解决方案。所有 WPF 窗口都很好,但所有 WinForm 缩放都错误。
它发生在 WPF 中的 WinForms 应用程序上,但也作为独立的 WinForms。 .NET 4.7.2 中的两个应用程序。所以它应该像所有其他答案中所解释的那样工作,但事实并非如此。
这是我的设置
我最终得出的解决方案是
在 app.manifest 文件中使用“unaware”而不是“PerMonitorV2”
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
The final solution I ended with is using "unaware" instead of "PerMonitorV2"
In the app.manifest file
项目文件添加(yourproject.csproj):
Program.cs 文件(如果存在)
将其释放。删除此行。因为它设置了 bootstrap 的 dpi 首选项,所以将其自定义为项目的首选项。
MainForm.cs构造函数add
并从MainForm.designer.cs中删除
这些显然适用于 .Net 6 Winform 应用程序。
Project file add (yourproject.csproj):
Program.cs file if exists
Make it free. Remove this line. Because it sets up bootstrap's dpi preferences, custom it to project's preferences.
MainForm.cs constructor function add
And remove from MainForm.designer.cs
These work for .Net 6 Winform application clearly.
由于 Winform 应用程序表单可能包含控件和图像,因此允许系统调整窗口大小并不是一个解决方案,但如果您能够设法为每个 DPI 分辨率创建一个表单,并具有适当缩放的图像...这不是一个好主意,因为随着屏幕尺寸的增大,字体尺寸会减小。
当使用不同的 DPI 分辨率时,系统会强制您的表单重新定义其控件的大小、位置和字体,但不包括图像,解决方案是在运行时加载时更改表单的 DPI,以便一切都恢复到原始大小和位置。
这是可能的解决方案,我已经使用纸牌游戏应用程序对其进行了测试,其中有大约 80 个图像按钮、TabControls 等。
在每个表单 form_Load 事件中,添加以下代码片段:
此外,在同一台计算机上测试各种分辨率而无需重新启动的快速技巧:
从控制面板更改分辨率。
不要重启!相反,请关闭您的会话并使用同一用户打开一个新会话。
还有另一个警告:如果您在运行时设置控件的大小和位置,那么您应该将相同的 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:
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.