.NET WinForms High DPI Scaling - как заставить формы правильно отображаться после изменения настроек отображения?

У меня есть приложение WinForms, встроенное в .NET Core 3.1, которое отлично работает на дисплеях с высоким разрешением. Моя проблема заключается в том, что всякий раз, когда в Windows добавляется или удаляется новый дисплей, формы снова приобретают этот нечеткий вид. Перезапуск приложения решает эту проблему, но я хотел бы соответствующим образом перерисовывать формы всякий раз, когда это происходит.

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

Подписка на событие Windows DisplaySettingsChanged выглядит так:

using Microsoft.Win32;
(...)
SystemEvents.DisplaySettingsChanged += new EventHandler(UpdateDpiOnOpenForms);

А затем добавил метод обработчика событий, который я не мог заставить работать:

public static void UpdateDpiOnOpenForms(object sender, EventArgs e)
{
    foreach (Form f in Application.OpenForms) 
    { 
        //What would the correct command be here?
    }
}

Как заставить все открытые формы перерисовываться/перерисовываться с использованием новых настроек высокого разрешения по умолчанию, как это делается после запуска приложения?


person t4r4z0k    schedule 16.02.2021    source источник
comment
Обратите внимание, что класс Form уже предоставляет RescaleConstantsForDpi(), OnGetDpiScaledSize(), OnDpiChanged() и OnDpiChangedAfterParent, OnDpiChangedBeforeParent из Control. Кроме того, DpiChanged и другие связанные события. -- Как вы установили DpiAwareness вашего приложения?   -  person Jimi    schedule 16.02.2021
comment
Все остается так, как определено в шаблоне проекта .NET WinForms. Я использую Visual Studio 2019 версии 16.8.4. Нужно ли мне создавать файл манифеста и явно объявлять совместимость с высоким разрешением даже в .NET Core?   -  person t4r4z0k    schedule 16.02.2021
comment
Application.SetHighDpiMode(). -- Поскольку вы все еще создаете свое приложение, мое предложение (просто предложение и только мое) состоит в том, чтобы вместо этого использовать .Net 5+ (или .Net Framework 4.8), оставьте .Net Core 3.1. -- Автомасштабирование до точек на дюйм.   -  person Jimi    schedule 16.02.2021
comment
На самом деле эта команда выполняется, когда приложение запускается до загрузки какой-либо формы: Application.SetHighDpiMode(HighDpiMode.SystemAware);   -  person t4r4z0k    schedule 16.02.2021
comment
Это потому, что app.config не рассматривается в .Net Core. app.manifest является и переопределяет любой Application.SetHighDpiMode(). В идеале вы должны установить HighDpiMode.PerMonitorV2, который ограничен некоторыми более новыми версиями Windows 10. Если вы планируете поддерживать больше версий системы, это необходимо указать в файле app.manifest. Довольно сложно все время делать все правильно (в основном потому, что этот вопрос по своей сути не решен). См.: Установка поддержки DPI по умолчанию для процесса, [...]   -  person Jimi    schedule 16.02.2021
comment
[...] Разработка настольных приложений с высоким разрешением для Windows и Поддержка высокого разрешения в Windows Forms. Если это становится запутанным, это потому, что так оно и есть (опять же, по своей сути). Требуется много испытаний.   -  person Jimi    schedule 16.02.2021
comment
Поскольку, очевидно, вы не настроили свое приложение для поддержки High Dpi Awareness, вам нужно начать с настройки, а затем перейти к конструктору, который должен учитывать масштабирование Dpi, которое происходит во время выполнения. Создайте свое приложение с масштабированием 100% (всегда), масштабируйте до Dpi, используйте контейнеры (Panels, TableLayoutPanels, FlowLayoutPanels и другие пользовательские контейнеры) для компоновки и привязки ваших элементов управления: не позволяйте им плавать вокруг ( Когда-либо). Обработайте и установите шрифт явно, используя шрифт, созданный для этого (пользовательский интерфейс Segoe, пользовательский интерфейс Microsoft Yahei и т. д. -> часть UI выдает его). Тестируйте много.   -  person Jimi    schedule 16.02.2021
comment
См. также, например, Автоматическое масштабирование в Windows Forms. Обратите внимание на информационное поле Important, если вы переключите селектор версии на .Net 5.   -  person Jimi    schedule 16.02.2021
comment
Как я уже говорил в вопросе: приложение отлично масштабируется при запуске в статической среде (поэтому я предполагаю, что оно объявляет себя системой с поддержкой DPI). Проблема возникает, когда я переключаюсь с внутреннего дисплея ноутбука на внешний дисплей или расширяю рабочий стол. Вот когда приложение необходимо перезапустить, чтобы пользовательский интерфейс отображался четко. Эта проблема решена в WPF?   -  person t4r4z0k    schedule 16.02.2021
comment
Вот для чего нужен HighDpiMode.PerMonitorV2. ПЛЮС приложение, разработанное для поддержки масштабирования Dpi.   -  person Jimi    schedule 16.02.2021


Ответы (1)


Используйте метод Control.Invalidate().

Делает недействительной указанную область элемента управления (добавляет ее в область обновления элемента управления, которая является областью, которая будет перерисована при следующей операции рисования) и вызывает отправку сообщения о рисовании элементу управления. При необходимости делает недействительными дочерние элементы управления, назначенные элементу управления.

https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.invalidate?view=net-5.0

person Oscar    schedule 16.02.2021
comment
Метод Invalidate() не сработал. Я даже пытался перебирать один из элементов управления открытой формы один за другим, и это все равно не помогло. - person t4r4z0k; 16.02.2021