【问题标题】:WinForm changes size at runtime... high DPI related?WinForm 在运行时改变大小...高 DPI 相关?
【发布时间】:2018-09-20 13:05:52
【问题描述】:

当我在视网膜 MacBook Pro 上的虚拟机中在 Windows 中运行我的 WinForm 应用程序时,窗体的大小在运行时缩小,而按钮同时向外移动。这可能会导致底部边缘的按钮滑到窗口边缘下方,看不见。由于它们是底部锚定的,因此它们完全无法访问。从 Windows 原生桌面运行时,应用程序通常表现良好。

这仅发生在表单上的 字体DPI AutoScaleMode 设置中。使用 InheritNone,表单及其内容非常庞大,但与我的设计方式成正比。

我已经用一个全新的模板 WinForm 应用程序复制了这个,除了调整表单大小并放入一个按钮之外什么都不做。如何在不改变尺寸的情况下让应用缩放?

这是designer.cs中的InitializeComponent()方法:

  private void InitializeComponent()
  {
        this.sendButton = new System.Windows.Forms.Button();
        this.SuspendLayout();
        // 
        // sendButton
        // 
        this.sendButton.Location = new System.Drawing.Point(60, 856);
        this.sendButton.Margin = new System.Windows.Forms.Padding(4);
        this.sendButton.MinimumSize = new System.Drawing.Size(200, 60);
        this.sendButton.Name = "sendButton";
        this.sendButton.Size = new System.Drawing.Size(200, 62);
        this.sendButton.TabIndex = 1004;
        this.sendButton.Text = "Send";
        this.sendButton.UseVisualStyleBackColor = true;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(282, 981);
        this.Controls.Add(this.sendButton);
        this.Name = "Form1";
        this.Text = "Form1";
        this.ResumeLayout(false);

  }

这是设计器中的表单截图:

在运行时:

【问题讨论】:

  • 使用锚点。或者一个 Dock-Filled TableLayoutPanel。
  • @LarsTech 我确实锚定到底部,但是当我这样做时,控件被卡在该位置超出范围
  • 我没有看到您的设计器代码中使用了 Anchor 属性。如果您要在不同的 DPI 环境中进行设计,TableLayoutPanel 可以让事情变得更简单。
  • @LarsTech 我没有将它包含在我的示例中,因为它不会影响行为。布局并不是真正的问题——表单的行为不符合预期。我将尝试改写问题以使其更清楚。
  • 嗯,确实如此。如果您在 Retina Mac 上的某个位置放置一个按钮,它可能是您戴尔上的不同位置。一个 Dock-Filled TableLayoutPanel 会有所帮助,因为它可以按百分比进行布局。您可以尝试使用表单的 AutoScaleMode。

标签: c# winforms visual-studio-2017


【解决方案1】:

此问题不是由重新缩放问题引起的,它更为普通。是Form.SetBoundsCore() method引起的,我链接到问题说明。

您可以使用 SystemInformation 类查看它,对边界应用约束,因此窗口不能太小,也不能大于监视器。此方法在您的程序中运行两次。第一次是表单的 InitializeComponent() 方法运行时。请注意,此时表单的尺寸仍然太大,直到重新缩放后才适合显示器。

也许你闻到了这个错误,它太早地应用了大小约束,在 ScaleControl() 方法计算新大小之前。所以你的设计 Size.Height 会被显示器的大小剪裁。 然后窗口被缩放以适应 DPI 差异,结果高度太小了。

通常您可以覆盖像 SetBoundsCore() 这样的虚拟方法,但是绕过 base.SetBoundsCore() 调用并不是很实用。这种方法发生了太多事情,绕过它可能会导致其他错误。实际的解决方法几乎太愚蠢了,无法提及。从链接代码中请注意,除非表单的 WindowState 设置为正常,否则它不会应用大小约束。因此,您可以通过在设计器中将 WindowState 设置为 Minimized 来绕过它。然后你所要做的就是在 Load 事件中将其设置为正常,它会在窗口重新缩放后触发:

    protected override void OnLoad(EventArgs e) {
        this.WindowState = FormWindowState.Normal;
        base.OnLoad(e);
    }

呵呵。扩大规模总是比缩小规模要容易得多。

如果我不发布更典型的 dpiAware 代码,那就太失职了。在这种情况下类似于:

    protected override void OnLoad(EventArgs e) {
        this.ClientSize = new Size(button1.Width + 2 * button1.Left, button1.Bottom + 10);
        base.OnLoad(e);
    }

因此,只需强制客户区显示控件即可。您可以选择底部的控件和最右侧的控件。

【讨论】:

  • 我猜没有办法阻止 Minimized -> Normal GUI 烟花的发生。
  • 不知道为什么会出现问题,它发生在窗口还不可见的时候。没有可见的文物或烟花。
  • 对我来说,表单会从任务栏出现。
  • 啊,我在系统设置中关闭了动画选项。大鼠。让我们称之为功能。
  • 我想知道除了OnLoad 之外是否还有一点可以将窗口状态改回......
【解决方案2】:

我认为问题在于 AutoScaleMode。对 Form1 中的代码进行以下更改:

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

这可能会解决您的问题。 SizeF 用于Font,对于100% 字体大小,其值为(13F, 8F)

【讨论】:

    猜你喜欢
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多