it-swarm.com.ru

WinForms 4K и 1080p масштабирования/высокий DPI?

Итак, вот сценарий: я пытаюсь сделать так, чтобы все мои формы (которые являются Winforms) выглядели хорошо в 4K и 1080p, также известном как high-DPI или «dpi -ware». У меня (для целей этого вопроса) есть три формы: frmCompanyMasterEdit, которая наследуется от frmBaseEdit, которая наследуется от frmBase, которая наследует форму System.Windows.Forms.Form

Я попробовал старый способ, сделав мое приложение с поддержкой DPI в манифесте:

  <application xmlns="urn:schemas-Microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.Microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
  </application>

Таким образом, если не считать мелких проблем с привязкой, которые я могу исправить, форма выглядит идеально при 4K и выглядит так же, но немного размыто в 1080p. Вот это в 4K: 4K и старые и новые способы

Во всяком случае, поэтому я поцарапал это и попробовал это новым способом, описанным в .NET 4.7, нацеливаясь на структуру 4.7 и добавив следующий код: 

в app.config

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

к app.manifest

<!-- Windows 10 compatibility -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />

а также удаление старого кода из app.manifest, чтобы не перекрывать новый способ .NET 4.7. Я позаботился о том, чтобы поместить код в соответствующие места . Так что здесь форма выглядит хорошо в 4K, как на картинке выше, но теперь в 1080p она очень увеличена, как показано здесь: 1080p new way

Так или иначе, форма выглядит великолепно в 4k, за исключением незначительных проблем с привязкой, и она либо (старый способ) имеет правильный размер, но немного размыта в 1080p, либо не размыта в 1080p, но действительно увеличена. I также пришлось изменить эти две строки во всех файлах designer.vb, как показано ниже:

Me.AutoScaleDimensions = New System.Drawing.SizeF(96.0!, 96.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi

Я не знаю, почему я не могу заставить его выглядеть уместно в 1080p. Как я уже сказал, я нацеливаюсь на платформу 4.7 .NET. Я использую соответствующую версию Windows 10 (версия 1709/Creator's edition). 1080p масштабируется на 100%. Также у нас нет ресурсов для обновления до WPF.

5
Chris K

Я успешно добавил поддержку DPI для 2 моих приложений Winforms, нацеленных на .NET 4.5 и 4.7 соответственно.

В прошлом я безуспешно пытался добавить поддержку через файл манифеста. К счастью, я нашел следующее решение:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WinformsApp
{
    static class Program
    {
        [DllImport("Shcore.dll")]
        static extern int SetProcessDpiAwareness(int PROCESS_DPI_AWARENESS);

        // According to https://msdn.Microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx
        private enum DpiAwareness
        {
            None = 0,
            SystemAware = 1,
            PerMonitorAware = 2
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            SetProcessDpiAwareness((int)DpiAwareness.PerMonitorAware);

            Application.Run(new MainForm());
        }
    }
}

Приведенный выше код - это то, как должен выглядеть ваш файл Program.cs. Конечно, вам придется перенести это на VB, но это должно быть достаточно легко сделать.

Это прекрасно работало в Windows 10 без необходимости каких-либо других модификаций.

В одном из двух приложений Winforms я рендерил строки через класс Graphics, используя пиксельные координаты, что приводило к смещению моих строк. Исправление было довольно тривиальным:

private void DrawString(Graphics g, string text, int x, int y)
{
    using (var font = new Font("Arial", 12))
    using (var brush = new SolidBrush(Color.White))
        g.DrawString(text, font, brush, LogicalToDeviceUnits(x), LogicalToDeviceUnits(y));
}

По сути, мне пришлось использовать Control.LogicalToDeviceUnits(int value) для масштабирования координат пикселей.

Кроме этого, мне не нужно было трогать мой код вообще.

3
Nolonar

В моем случае я столкнулся со слишком большим количеством глюков при рекомендованном подходе к настройке процесса распознавания DPI: минимальный размер формы не будет работать правильно, случайные ошибки при перемещении форм по мониторам с различным DPI, обрезка форм без видимой причины, шрифт Segoe Пользовательский интерфейс не будет правильно масштабироваться, привязка элементов управления в контейнерах сплиттера заставляет все перемещаться в неправильном положении и т.д.

Существует также проблема, заключающаяся в том, что значки становятся меньше, и вам необходимо обновить код, чтобы выборочно загружать версии с более высоким разрешением для кнопок, ListView, TreeView и т.д.

Альтернатива, которую я в итоге использовал, - это использование настроек Windows 10 для переопределения поведения масштабирования с помощью «GDI Scaling». Это может быть объявлено в манифесте приложения.

Вот настройка, в которой вы можете сначала попробовать ее и посмотреть, соответствует ли она вашим потребностям:

 enter image description here

Этот параметр можно установить автоматически, изменив файл app.manifest в своем проекте и добавив следующую запись:

<asmv3:application>
  <asmv3:windowsSettings xmlns="http://schemas.Microsoft.com/SMI/2017/WindowsSettings">
    <gdiScaling>true</gdiScaling>
  </asmv3:windowsSettings>
</asmv3:application>

Код может выдать ошибку, что «asmv3» не распознается. Чтобы добавить пространство имен asmv3, измените ваш app.manifest, чтобы включить его:

До:

<Assembly manifestVersion="1.0" xmlns="urn:schemas-Microsoft-com:asm.v1">

После:

<Assembly manifestVersion="1.0" xmlns="urn:schemas-Microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-Microsoft-com:asm.v3">
0
FoundWaldoException