Форма Windows не масштабирует высоту, когда дисплей масштабируется на 150%

Я довел это до очень простого воспроизведения и не могу понять, что не так с этой формой. При запуске с разрешением 96 DPI / масштабом 100% все выглядит нормально:

введите здесь описание изображения

Но при запуске с разрешением 144 DPI / масштабом 150% (или даже 96 DPI / масштабом 150%) масштабируется все, кроме высоты формы:

введите здесь описание изображения

Первоначально я думал, что это проблема DPI, но после проверки того, что он воспроизводится с разрешением 96 DPI, я не уверен, что происходит.

В диалоговом окне или элементе управления не происходит ничего особенного, кроме конкретной настройки шрифта диалогового окна и установки AutoScaleMode в DPI. Форма находится внутри сборки, которая автоматически загружается приложением.

Я использую .NET 4.7.2 и Windows 10.

Вот код формы:

using System;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FormTestLib
{
    partial class ValidatingSplash : Form
    {
        public ValidatingSplash()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            this.CenterToParent();
        }
    }
}

Вот файл конструктора:

namespace FormTestLib
{
    public partial class ValidatingSplash
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ValidatingSplash));
            this.lblValidating = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // lblValidating
            // 
            this.lblValidating.Anchor = System.Windows.Forms.AnchorStyles.None;
            this.lblValidating.AutoSize = true;
            this.lblValidating.Location = new System.Drawing.Point(58, 45);
            this.lblValidating.Name = "lblValidating";
            this.lblValidating.Size = new System.Drawing.Size(166, 13);
            this.lblValidating.TabIndex = 7;
            this.lblValidating.Text = "Validating cached credentials...";
            // 
            // ValidatingSplash
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
            this.ClientSize = new System.Drawing.Size(274, 104);
            this.ControlBox = false;
            this.Controls.Add(this.lblValidating);
            this.Font = new System.Drawing.Font("Segoe UI", 8.25F);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "ValidatingSplash";
            this.Text = "Validating Credentials";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion
        private System.Windows.Forms.Label lblValidating;
    }
}

В app.config я устанавливаю DpiAwareness в соответствии с документами:

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

И в манифесте я устанавливаю совместимость:

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
  <application>
    <!-- Windows 10 compatibility -->
    <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
  </application>
</compatibility>

Все это согласно инструкции по поддержке высокого разрешения здесь.

Код приложения просто показывает диалог:

namespace TestApp
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // set the visual styles
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(true);

            ValidatingSplash Splash = new ValidatingSplash();
            Splash.ShowDialog();
        }
    }
}

Может ли кто-нибудь увидеть, что я могу делать неправильно или что мне не хватает?

Заранее спасибо!


person Bill Brooks    schedule 03.03.2019    source источник
comment
Удалить this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);. Вы можете найти настройки dpiAwareness в файле app.manifest. Даже если это больше не рекомендуется, попробуйте. Откомментируйте то, что вы предпочитаете. Сомневаюсь, что вы нашли это: Application.SetCompatibleTextRenderingDefault(true); в Документах.   -  person Jimi    schedule 04.03.2019
comment
Это произойдет, если вы измените DPI перед запуском программы или только если масштабирование изменится во время работы программы?   -  person Joel Coehoorn    schedule 04.03.2019
comment
Кроме того, этот вопрос является полезным ресурсом: stackoverflow.com/questions/22735174/   -  person Joel Coehoorn    schedule 04.03.2019
comment
Спасибо @JoelCoehoorn, я видел этот вопрос, но он не касается этого случая. Это происходит, если я закрою приложение, изменю масштаб, выйду из системы, войду снова и запущу программу. Это также происходит без выхода из системы/входа в систему, но я обнаружил, что достаточное количество циклов настройки масштаба без выхода из системы/входа в систему может привести к непредсказуемым результатам. Я не пробовал во время работы приложения.   -  person Bill Brooks    schedule 04.03.2019
comment
@ Джими, я попробовал твои предложения. Удаление AutoScaleDimensions просто приводит к диалоговому окну другого размера, но все еще слишком маленькому и обрезающему текст. Добавление/перемещение dpiAwareness в app.manifest не дало никакого эффекта. И хороший улов - параметр true для SetCompatibleTextRenderingDefault() был просто переменной, которую я попробовал некоторое время назад и случайно оставил. К сожалению, изменение его обратно на false, похоже, также не имеет никакого эффекта.   -  person Bill Brooks    schedule 04.03.2019
comment
Каковы реальные цифры? Может быть, вы достигли предела (например, высоты экрана??)   -  person TaW    schedule 04.03.2019
comment
Если вы используете приложение, файл конфигурации, попробуйте установить это: <add key="EnableWindowsFormsHighDpiAutoResizing" value="false" />. При включении поддержки DPI в app.config также включаются все дополнительные функции. Вот почему я предложил использовать только манифест для установки конкретной настройки dpiAwareness или просто dpiAware = true. Я думаю, что пропустил это: Форма находится внутри сборки, которая автоматически загружается приложением. Это также имеет последствия. Если что-то dpiAware, вам лучше иметь все, что работает таким образом.   -  person Jimi    schedule 04.03.2019
comment
Установка этого значения в false не имела никакого эффекта. Пробовал добавить конфигурационный файл для сборки, без разницы. Эта ссылка указывает что, если не указано иное, все потоки будут использовать процесс по умолчанию для определения dpi. Я не смог найти ничего, что указывало бы на последствия для сборок. Кажется, это проблема с dpiAwareness (даже если DPI не изменился), так как я могу удалить dpiAwareness из app.config, и проблема исчезнет.   -  person Bill Brooks    schedule 04.03.2019
comment
В коде дизайнера нашел оскорбительную строчку: this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; Если эту строчку закомментировать, то все работает как надо. Этот стиль границы не поддерживается, когда (или содержит ошибки, если) установлен определенный шрифт диалогового окна, а также включена поддержка DPI и масштабирование экрана. Может ли кто-нибудь подтвердить, действительно ли это ошибка или так задумано? Я не смог ничего найти в документах.   -  person Bill Brooks    schedule 04.03.2019
comment
Бонус: эта проблема возникает только в том случае, если масштабируется основной дисплей. В этом случае проблема возникает на всех мониторах (независимо от масштаба на каждом мониторе). Если основной дисплей не масштабируется, проблема не возникает ни на одном мониторе (даже на масштабированных мониторах). Кроме того, это происходит независимо от того, задан ли шрифт явно. То есть это происходит и с системным шрифтом по умолчанию.   -  person Bill Brooks    schedule 04.03.2019


Ответы (1)


Чтобы следовать рекомендациям Microsoft и обеспечить поддержку High DPI для вашего приложения, вы должны изменить несколько вещей. Прежде всего, в файле формы конструктора измените AutoScaleDimensions на AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);. И AutoScaleMode на this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;.

В приложении просто используйте Application.SetCompatibleTextRenderingDefault(false);

Я также добавил небольшую поправку для настройки ClientSize формы. НастроитьШиринуКлиентаToDPIScale(). В зависимости от масштаба DPI ширина клиентской формы изменяется в соответствии с коэффициентом DPI.

Весь код указан ниже.

Файл App.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1"/>
    </startup>
      <System.Windows.Forms.ApplicationConfigurationSection>
    <add key="DpiAwareness" value="PerMonitorV2" />
  </System.Windows.Forms.ApplicationConfigurationSection>
</configuration>

Код формы:

using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FormTestLib
{
    public partial class ValidatingSplash : Form
    {
        public ValidatingSplash()
        {
            InitializeComponent();

            AdjustClientWidthToDPIScale();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            this.CenterToParent();
        }

        private void AdjustClientWidthToDPIScale()
        {
            double dpiKoef = Graphics.FromHdc(GetDC(IntPtr.Zero)).DpiX / 96f;

            int compansatedWidth = (int)(ClientSize.Width * dpiKoef);


            this.ClientSize = new Size(compansatedWidth, this.ClientSize.Height);
        }

        [DllImport("User32.dll")]
        private static extern IntPtr GetDC(IntPtr hWnd);
    }
}

Дизайнер форм:

    namespace FormTestLib
{
    partial class ValidatingSplash
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ValidatingSplash));
            this.lblValidating = new System.Windows.Forms.Label();
            this.SuspendLayout();

            // 
            // lblValidating
            // 
            this.lblValidating.Anchor = System.Windows.Forms.AnchorStyles.None;
            this.lblValidating.AutoSize = true;
            this.lblValidating.Location = new System.Drawing.Point(58, 45);
            this.lblValidating.Name = "lblValidating";
            this.lblValidating.Size = new System.Drawing.Size(166, 13);
            this.lblValidating.TabIndex = 7;
            this.lblValidating.Text = "Validating cached credentials...";
            // 
            // ValidatingSplash
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(274, 104);
            this.ControlBox = false;
            this.Controls.Add(this.lblValidating);
            this.Font = new System.Drawing.Font("Segoe UI", 8.25F);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            //this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "ValidatingSplash";
            this.Text = "Validating Credentials";
            this.ResumeLayout(false);
            this.PerformLayout();
        }

        #endregion
        private System.Windows.Forms.Label lblValidating;
    }
}

Код приложения:

[STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        ValidatingSplash Splash = new ValidatingSplash();
        Splash.ShowDialog();
    }
person Andrew Patynko    schedule 12.03.2019