Як налаштувати додаток для правильного запуску на машині з високою настройкою DPI (наприклад, 150%)?


101

Я створив простий додаток Winforms в C #. Коли я запускаю програму на машині з високими налаштуваннями DPI (наприклад, 150%), програма збільшується. Все йде нормально! Але замість візуалізації шрифтів з більшим розміром шрифту, всі тексти теж просто збільшуються. Це, звичайно, призводить до дуже розмитого тексту (на всіх елементах управління, як кнопки тощо).

Чи не повинні Windows піклуватися про правильне відображення текстів? Наприклад, рядок заголовка моєї програми стає чітким та чітким.

Відповіді:


131

Після того, як ви перейдете 100% (або 125%, якщо встановлено прапорець "Масштабування DPI у стилі XP"), Windows за замовчуванням бере на себе масштабування вашого інтерфейсу. Це робиться завдяки тому, що ваша програма надає свій результат в растрову карту і виводить цю растрову карту на екран. Зміна масштабування цього растрового зображення неминуче виглядає як текст нечітким. Функція під назвою "віртуалізація DPI", вона підтримує старі програми, які можна використовувати на моніторах високої роздільної здатності.

Ви повинні чітко повідомити, що ви можете обробляти більш високі налаштування DPI, додаючи <dpiAware>елемент у свій маніфест. Сторінка MSDN тут, але вона не є повною, оскільки вона опускає налаштування UAC. Проект + Додати новий елемент, виберіть "Файл маніфесту програми". Відредагуйте текст маніфесту або скопіюйте / вставте це:

<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
    <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
        <security>
            <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
                <requestedExecutionLevel level="asInvoker" uiAccess="false" />
            </requestedPrivileges>
        </security>
    </trustInfo>
    <asmv3:application>
        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
            <dpiAware>true</dpiAware>
        </asmv3:windowsSettings>
    </asmv3:application>
</assembly>

Ви також можете встановити SetProcessDPIAware () у вашому методі Main (), необхідному, наприклад, якщо ви розгортаєтеся з ClickOnce:

    [STAThread]
    static void Main() {
        if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware();
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());             // Edit as needed
    }

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern bool SetProcessDPIAware();

ОНОВЛЕННЯ, ця загальна потреба, нарешті, трохи легша, якщо ви використовуєте VS2015 Update 1 або новішої версії. Доданий маніфест вже має відповідну директиву, просто видаліть коментарі.


Ключове слово для пошуку, щоб я міг знайти цю посаду назад: dpiAware


Дякуємо, ваше рішення працює чудово. Єдина проблема, яка залишилася - це те, що всі зображення тепер у своїх оригінальних розмірах. Напевно, мені доведеться знайти спосіб додати додаткові "сітківки" -концентрації в мій графічний інтерфейс ...
Борис

@HansPassant У мене така ж проблема із розмитими шрифтами, і після застосування цього рішення мій елемент керування не змінюється, і вони не можуть поміститися. Як змусити обох працювати?
gajo357

2
Для тих, хто досліджує це безумство Win8, SetProcessDPIAwareзастаріле, і воно також не працює належним чином (принаймні, не в Win8.1), викликаючи непередбачуване масштабування на різних елементах управління. Настійно рекомендую натомість використовувати маніфестний підхід.
Джейсон Вільямс

5
Hmya, Windows 8.1 придбав DPI за монітором. Я не усвідомлював, що мені це потрібно.
Ганс Пасант

1
Якщо ви збираєтеся використовувати ClickOnce для розгортання, ви не можете використовувати опцію dpiAware в маніфесті, замість цього використовуйте SetProcessDPIAware ().
Матіас

17

Програми можна розробляти в двох різних режимах.

Перший - оголосити нашу заяву такою, що не відповідає DPI (не декларуючи нічого, за замовчуванням цього не потрібно). У цьому випадку операційна система подасть нашу програму під очікувані 96 DPI, а потім зробить масштабування растрових зображень, про які ми говорили раніше. В результаті вийде розмита програма, але з правильним компонуванням.

Другий варіант - оголосити програму такою, що відома DPI. У цьому випадку ОС не здійснюватиме масштабування та дозволить вашій програмі відображатись відповідно до оригінальної DPI екрана. У випадку оточення за монітором-DPI вашій програмі буде надано найвищий DPI з усіх екранів, тоді ця растрова карта буде зменшена до належного розміру для кожного монітора. Зменшення масштабу призводить до кращого перегляду, ніж збільшення масштабу, але ви все одно можете помітити певну нечіткість.

Якщо ви хочете цього уникнути, ви повинні оголосити свою заяву як на монітор-DPI. Тоді ви повинні виявити, коли ваша програма перетягується через різні монітори та відображати відповідно до DPI поточного.

Декларація обізнаності щодо DPI робиться у файлі маніфесту.

перейдіть за наступним посиланням stackoverflow


що робити, якщо користувачі мають відновлене розмір вікна та переміщують його, щоб його частини знаходились на різних моніторах? чи потрібно нам рендерувати все двічі і використовувати межі монітора як обмежувальні поля? скільки цього покривають бібліотеки winforms?
Cee McSharpface

4

Використовуючи .NET Framework 4.7 та оновлення Windows 10 Creators (1703) або новіших версій, ви повинні виконати такі дії, щоб налаштувати високу підтримку DPI для програми Windows Form:

Декларуйте сумісність з Windows 10.

Для цього додайте у manifestфайл наступне :

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

Увімкніть інформацію про DPI за монітором у app.configфайлі.

Windows Forms представляє новий елемент System.Windows.Forms.ApplicationConfigurationSection для підтримки нових функцій та налаштувань, доданих, починаючи з .NET Framework 4.7. Щоб скористатися новими функціями, що підтримують високу DPI, додайте наступне до файлу конфігурації програми.

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

Важливо

У попередніх версіях .NET Framework ви використовували маніфест, щоб додати високу підтримку DPI. Цей підхід більше не рекомендується, оскільки він перекриває налаштування, визначені у файлі app.config.

Викличте статичний метод EnableVisualStyles.

Це має бути першим викликом методу у точці входу програми. Наприклад:

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());   
}

Перевагою цього є підтримка динамічних сценаріїв DPI, в яких користувач змінює DPI або коефіцієнт масштабу після запуску програми Windows Forms.

Джерело: Підтримка високої DPI у формах Windows


3

Жодна з цих пропозицій не працювала для мене, але щось сталося після того, як я видалив Form.Font = new... з Form.Design.cs, форма почала правильно змінювати масштаб, вона працює, якщо шрифт визначений у конструкторі чи взагалі немає. Чому? хтось інший, можливо, зможе пояснити, я просто можу поговорити про зміни, які я вніс, і зайняв кілька хвилин, щоб зрозуміти, що це першопричина форми, над якою я працював. Сподіваюся, це допомагає.


2

Оскільки принаймні Visual Studio 2017 вам просто потрібно додати файл маніфесту та відмінити цей розділ:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
</application>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.