如何编写自动缩放到系统字体和 dpi 设置的 WinForms 代码? [英] How to write WinForms code that auto-scales to system font and dpi settings?

查看:30
本文介绍了如何编写自动缩放到系统字体和 dpi 设置的 WinForms 代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简介: 有很多评论说WinForms 不能很好地自动缩放到 DPI/字体设置;切换到 WPF."但是,我认为这是基于 .NET 1.1;看起来他们实际上在 .NET 2.0 中实现自动缩放方面做得很好.至少基于我们迄今为止的研究和测试.但是,如果你们中的一些人知道得更好,我们很乐意听取您的意见.(请不要争论我们应该切换到 WPF ......现在这不是一个选项.)

Intro: There's a lot of comments out there that say "WinForms doesn't auto-scale to DPI/font settings well; switch to WPF." However, I think that is based on .NET 1.1; it appears they actually did a pretty good job of implementing auto-scaling in .NET 2.0. At least based on our research and testing so far. However, if some of you out there know better, we'd love to hear from you. (Please don't bother arguing we should switch to WPF... that's not an option right now.)

  • WinForms 中的哪些内容不能正确自动缩放,因此应该避免?

  • What in WinForms does NOT auto-scale properly and therefore should be avoided?

程序员在编写 WinForms 代码时应该遵循哪些设计准则,以便它能够很好地自动缩放?

What design guidelines should programmers follow when writing WinForms code such that it will auto-scale well?

请参阅下面的社区维基答案.

其中有哪些是不正确的或不充分的?我们应该采用任何其他准则吗?还有其他需要避免的模式吗?对此的任何其他指导将不胜感激.

Are any of those incorrect or inadequate? Any other guidelines we should adopt? Are there any other patterns that need to be avoided? Any other guidance on this would be very appreciated.

推荐答案

不支持正确缩放的控件:

  • Label 继承了 AutoSize = FalseFont.在控件上显式设置 Font,使其在属性"窗口中以粗体显示.
  • ListView 列宽不缩放.覆盖表单的 ScaleControl 来代替它.请参阅此答案
  • SplitContainerPanel1MinSizePanel2MinSizeSplitterDistance 属性
  • TextBox 继承了 MultiLine = TrueFont.在控件上显式设置 Font,使其在属性"窗口中以粗体显示.
  • ToolStripButton 的图像.在表单的构造函数中:

    Controls which do not support scaling properly:

    • Label with AutoSize = False and Font inherited. Explicitly set Font on the control so it appears in bold in the Properties window.
    • ListView column widths don't scale. Override the form's ScaleControl to do it instead. See this answer
    • SplitContainer's Panel1MinSize, Panel2MinSize and SplitterDistance properties
    • TextBox with MultiLine = True and Font inherited. Explicitly set Font on the control so it appears in bold in the Properties window.
    • ToolStripButton's image. In the form's constructor:

      • 设置 ToolStrip.AutoSize = False
      • 根据CreateGraphics.DpiX.DpiY
      • 设置ToolStrip.ImageScalingSize
      • 如果需要,设置 ToolStrip.AutoSize = True.

      有时 AutoSize 可以保留在 True 但有时它无法在没有这些步骤的情况下调整大小.使用 .NET Framework 4.5.2EnableWindowsFormsHighDpiAutoResizing.

      Sometimes AutoSize can be left at True but sometimes it fails to resize without those steps. Works without that changes with .NET Framework 4.5.2 and EnableWindowsFormsHighDpiAutoResizing.

      • 所有 ContainerControl 必须设置为相同的 AutoScaleMode = Font.(字体将处理 DPI 更改和系统字体更改尺寸设置;DPI 将仅处理 DPI 更改,而不处理对系统字体大小设置.)

      • All ContainerControls must be set to the same AutoScaleMode = Font. (Font will handle both DPI changes and changes to the system font size setting; DPI will only handle DPI changes, not changes to the system font size setting.)

      所有 ContainerControls 也必须设置为相同的 AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);,假设 96dpi(见下一个项目符号)和 MS 的默认字体无衬线字体(见下方的项目符号二).这是设计师自动添加的根据您打开设计器的 DPI...我们许多最古老的设计师文件.也许 Visual Studio .NET(VS 2005 之前的版本)没有正确添加.

      All ContainerControls must also be set with the same AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);, assuming 96dpi (see the next bullet) and default Font of MS Sans Serif (see the bullet two down). That is auto-added by the designer based on the DPI you open the designer in... but was missing from many of our oldest designer files. Perhaps Visual Studio .NET (the version before VS 2005) was not adding that in properly.

      在 96dpi 中完成所有设计师的工作(我们也许可以切换到120dpi;但互联网上的智慧说坚持96dpi;在那里进行实验;按照设计,它应该无关紧要,因为它只是更改了设计器插入的 AutoScaleDimensions 行).要将 Visual Studio 设置为在高分辨率显示器上以虚拟 96dpi 运行,找到它的.exe文件,右键编辑属性,在兼容性下选择覆盖高 DPI 缩放行为.缩放执行者:系统".

      Do all your designer work in 96dpi (we might be able to switch to 120dpi; but the wisdom on the internet says to stick to 96dpi; experimentation is in order there; by design, it shouldn't matter as it just changes the AutoScaleDimensions line that the designer inserts). To set Visual Studio to run at a virtual 96dpi on a high-resolution display, find its .exe file, right-click to edit properties, and under Compatibility select "Override high DPI scaling behavior. Scaling performed by: System".

      请确保您永远不会在容器级别设置字体...仅在如果您想要除 MS Sans Serif 之外的应用程序范围的默认字体,请在最基础的 Form 的构造函数中使用叶控件或.(在容器上设置字体似乎关闭该容器的自动缩放,因为它按字母顺序出现在 AutoScaleMode 和 AutoScaleDimensions 设置之后.)请注意,如果您确实更改了最基础 Form 的构造函数中的 Font,这将导致您的 AutoScaleDimensions 的计算方式与 6x13 不同;特别是,如果您更改为 Segoe UI(Win 10 默认字体),那么它将是 7x15……您需要触摸设计器中的每个表单,以便它可以重新计算该 .designer 文件中的所有尺寸,包括AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);.

      Be sure you never set the Font at the container level... only on the leaf controls OR in the constructor of your most base Form if you want an application-wide default Font other than MS Sans Serif. (Setting the Font on a Container seems to turn off the auto-scaling of that container because it alphabetically comes after the setting of AutoScaleMode and AutoScaleDimensions settings.) NOTE that if you do change the Font in your most base Form's constructor, that will cause your AutoScaleDimensions to compute differently than 6x13; in particular, if you change to Segoe UI (the Win 10 default font), then it will be 7x15... you will need to touch every Form in the Designer so that it can recompute all the dimensions in that .designer file, including the AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);.

      不要使用锚定到用户控件的锚RightBottom...定位不会自动缩放;相反,放下面板或其他容器到您的 UserControl 并将您的其他控件锚定到该小组;让面板使用 Dock RightBottomFill用户控件.

      Do NOT use Anchor Right or Bottom anchored to a UserControl... its positioning will not auto-scale; instead, drop a Panel or other container into your UserControl and Anchor your other Controls to that Panel; have the Panel use Dock Right, Bottom, or Fill in your UserControl.

      只有在ResumeLayout结尾时的Controls列表中的控件InitializeComponent 被调用将自动缩放...如果你动态添加控件,然后需要SuspendLayout();AutoScaleDimensions = new SizeF(6F, 13F); AutoScaleMode = AutoScaleMode.Font;ResumeLayout(); 在你添加它之前在那个控件上.和你的如果您不使用 Dock,也需要调整定位模式或布局管理器,如 FlowLayoutPanelTableLayoutPanel.

      Only the controls in the Controls lists when ResumeLayout at the end of InitializeComponent is called will be auto-scaled... if you dynamically add controls, then you need to SuspendLayout(); AutoScaleDimensions = new SizeF(6F, 13F); AutoScaleMode = AutoScaleMode.Font; ResumeLayout(); on that control before you add it in. And your positioning will also need to be adjusted if you are not using Dock modes or a Layout Manager like FlowLayoutPanel or TableLayoutPanel.

      ContainerControl 派生的基类应该将 AutoScaleMode 设置为 Inherit(在类 ContainerControl; 但不是设计者设置的默认值).如果您将其设置为其他任何内容,然后您的派生类尝试将其设置为 Font(应该如此),那么将其设置为 Font 的行为将清除设计者对 的设置AutoScaleDimensions,导致实际关闭自动缩放!(本指南与之前的指南相结合意味着您永远无法在设计器中实例化基类……所有类都需要设计为基类或叶类!)

      Base classes derived from ContainerControl should leave AutoScaleMode set to Inherit (the default value set in class ContainerControl; but NOT the default set by the designer). If you set it to anything else, and then your derived class tries to set it to Font (as it should), then the act of setting that to Font will clear out the designer's setting of AutoScaleDimensions, resulting in actually toggling off auto-scaling! (This guideline combined with the prior one means you can never instantiate base classes in a designer... all classes need to either be designed as base classes or as leaf classes!)

      避免在设计器中静态/使用 Form.MaxSize.Form 上的 MinSizeMaxSize 没有其他东西那么大.因此,如果您在 96dpi 中完成所有工作,那么当 DPI 较高时,您的 MinSize 不会引起问题,但可能没有您预期的那么严格,但是您的 MaxSize 可能会限制您的尺寸缩放,这可能会导致问题.如果您想要 MinSize == Size == MaxSize,请不要在设计器中执行此操作...在您的构造函数中执行此操作或 OnLoad 覆盖...同时设置 MinSizeMaxSize 到您适当缩放的大小.

      Avoid using Form.MaxSize statically / in the Designer. MinSize and MaxSize on Form do not scale as much as everything else. So, if you do all your work in 96dpi, then when at higher DPI your MinSize won't cause problems, but may not be as restrictive as you expected, but your MaxSize may limit your Size's scaling, which can cause problems. If you want MinSize == Size == MaxSize, don't do that in the Designer... do that in your constructor or OnLoad override... set both MinSize and MaxSize to your properly-scaled Size.

      特定PanelContainer 上的所有控件都应使用锚定或停靠.如果混合使用它们,该 Panel 完成的自动缩放通常会以微妙的奇怪方式出现异常行为.

      All of the Controls on a particular Panel or Container should either use Anchoring or Docking. If you mix them, the auto-scaling done by that Panel will often misbehave in subtle bizarre ways.

      当它进行自动缩放时,它会尝试缩放整个表单......但是,如果在该过程中它遇到屏幕尺寸的上限,这是一个硬限制,可以然后搞砸(剪辑)缩放.因此,您应该确保设计器中 100%/96dpi 的所有窗体的大小不超过 1024x720(对应于 1080p 屏幕上的 150% 或 4K 屏幕上的 Windows 推荐值 300%).但是你需要减去巨大的 Win10 标题/标题栏......所以更像是 1000x680 最大尺寸......在设计器中它就像 994x642 ClientSize.(因此,您可以对 ClientSize 执行 FindAll References 以查找违规者.)

      When it does its auto-scaling, it will be trying to scale the overall Form... however, if in that process it runs into the upper limit of the screen size, that is a hard limit that can then screw up (clip) the scaling. Therefore, you should make sure all Forms in the Designer at 100%/96dpi are sized no larger than 1024x720 (which corresponds to 150% on a 1080p screen or 300% which is the Windows recommended value on a 4K screen). But you need to subtract out for the giant Win10 title/caption bar... so more like 1000x680 max Size... which in the designer will be like 994x642 ClientSize. (So, you can do a FindAll References on ClientSize to find violators.)

      这篇关于如何编写自动缩放到系统字体和 dpi 设置的 WinForms 代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆