精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
服务方向
联系方式
I created an app for a small business. Some of the employees in the office can not see the form correctly. The reason is they have their DPI setting set to above 96dpi. Does anybody know of a way to control this? 我为一家小型企业创建了一个应用程序。办公室的某些员工无法正确看到该表格。原因是它们的DPI设置设置为96dpi以上。有人知道控制这种情况的方法吗?
For all of you who have experience with winforms apps, how do you control your form layout so that DPI does not affect the look of the application? 对于所有具有winforms应用程序经验的人,如何控制窗体布局,以使DPI不会影响应用程序的外观?
Assuming you do not try to honor the user's UI font choice (SystemFonts.IconTitleFont), and hard-code your forms for one font size only (e.g. Tahoma 8pt, Microsoft Sans Serif 8.25pt), you can set your form's AutoScaleMode to ScaleMode.Dpi. 假设您不尝试遵循用户的UI字体选择(SystemFonts.IconTitleFont),并且仅将窗体硬编码为一种字体大小(例如Tahoma 8pt,Microsoft Sans Serif 8.25pt),则可以将窗体的AutoScaleMode设置为ScaleMode.Dpi。
This will scale the size of the form and most of it child controls by the factor CurrentDpiSetting / 96 by calling Form.Scale(), which in turns calls the protected ScaleControl() method recursivly on itself and all child controls. ScaleControl will increase a control's position, size, font, etc as needed for the new scaling factor. 这将通过调用Form.Scale()来按CurrentDpiSetting / 96的比例缩放窗体及其子控件的大小,然后依次调用自身和所有子控件的受保护的ScaleControl()方法。 ScaleControl将根据新缩放因子的需要增加控件的位置、大小、字体等。
This is all well and good if you're just using controls. But if you ever use any hard-coded pixel sizes, you'll need to scale your pixel widths and lengths by the current scale factor of the form. Some examples of situations that could have hard-coded pixel sizes: 如果您仅使用控件,那么这一切都很好。但是,如果您使用任何硬编码的像素大小,则需要通过窗体的当前缩放比例来缩放像素的宽度和长度。可能具有硬编码像素大小的情况的一些示例:
If this is the case, you'll need to scale those hard-coded values by the "current scaling factor". Unfortunatly the "current" scale factor is not provided, we need to record it ourselves. The solution is to assume that initially the scaling factor is 1.0 and each time ScaleControl() is called, modify the running scale factor by the new factor. 如果是这种情况,则需要通过“当前缩放比例”缩放那些硬编码的值。不幸的是,没有提供“当前”比例因子,我们需要自己记录它。解决方案是假设初始缩放比例为1.0,并且每次调用ScaleControl()时,都使用新因子修改运行比例因子。
public class MyForm : Form { private SizeF currentScaleFactor = new SizeF(1f, 1f); protected override void ScaleControl(SizeF factor, BoundsSpecified specified) { base.ScaleControl(factor, specified); //Record the running scale factor used this.currentScaleFactor = new SizeF( this.currentScaleFactor.Width * factor.Width, this.currentScaleFactor.Height * factor.Height); Toolkit.ScaleListViewColumns(listView1, factor); } }
Initially the scaling factor is 1.0. If form is then scaled by 1.25, the scaling factor then becomes: 最初的缩放比例为1.0。如果将form缩放为1.25,则缩放因子变为:
1.00 * 1.25 = 1.25 //scaling current factor by 125%
If the form is then scaled by 0.95, the new scaling factor becomes 如果随后将窗体缩放0.95,则新的缩放因子变为
1.25 * 0.95 = 1.1875 //scaling current factor by 95%
The reason a SizeF is used (rather than a single floating point value) is that scaling amounts can be different in the x and y directions. If a form is set to ScaleMode.Font, the form is scaled to the new font size. Fonts can have different aspect ratios (e.g. Segoe UI is taller font than Tahoma). This means you have to scale x and y values independantly. 使用SizeF的原因(而不是单个浮点值)是因为缩放量在x和y方向上可能不同。如果将窗体设置为ScaleMode.Font,则该窗体将缩放为新的字体大小。字体可以具有不同的宽高比(例如,Segoe UI比Tahoma高)。这意味着您必须分别缩放x和y值。
So if you wanted to place a control at location (11,56), you would have to change your positioning code from: 因此,如果要将控件放置在位置(11,56),则必须将定位代码从以下位置更改:
Point pt = new Point(11, 56); control1.Location = pt;
to 至
Point pt = new Point( (int)Math.Round(11.0*this.scaleFactor.Width), (int)Math.Round(56.0*this.scaleFactor.Height)); control1.Location = pt;
The same applies if you were going to pick a font size: 如果要选择字体大小,则同样适用:
Font f = new Font("Segoe UI", 8, GraphicsUnit.Point);
would have to become: 必须成为:
Font f = new Font("Segoe UI", 8.0*this.scaleFactor.Width, GraphicsUnit.Point);
And extracting a 32x32 icon to a bitmap would change from: 而将32x32图标提取到位图的方式将从以下内容更改:
Image i = new Icon(someIcon, new Size(32, 32)).ToBitmap();
to 至
Image i = new Icon(someIcon, new Size( (int)Math.Round(32.0*this.scaleFactor.Width), (int)Math.Round(32.0*this.scaleFactor.Height))).ToBitmap();
etc. 等等
Supporting non-standard DPI displays is 支持非标准DPI显示器是
Set the AutoScaleMode to Inherit everywhere (ie all your UserControls) via a global search/replace, then set the AutoScaleMode to Dpi on your main form. 通过全局搜索/替换将AutoScaleMode设置为Inherit(到所有地方)(即,所有UserControl),然后在主窗体上将AutoScaleMode设置为Dpi。
I also find that layout containers work better than anchors for this type of situation. 我还发现,在这种情况下,布局容器比锚点更有效。
I know it's somewhat drastic, but consider to rewrite your app in WPF. WPF applications have the same look on every DPI setting. 我知道有些麻烦,但是请考虑使用WPF重写您的应用程序。 WPF应用程序在每个DPI设置上的外观都相同。