Como configurar um aplicativo para funcionar corretamente em uma máquina com uma configuração de alta DPI (por exemplo, 150%)?

101

Eu criei um aplicativo Winforms simples em C #. Quando executo o aplicativo em uma máquina com altas configurações de DPI (por exemplo, 150%), o aplicativo é ampliado. Por enquanto, tudo bem! Mas, em vez de renderizar as fontes com um tamanho de fonte maior, todos os textos também são ampliados. Isso, claro, leva a um texto muito borrado (em todos os controles, como botões, etc.).

O Windows não deveria se preocupar em renderizar os textos corretamente? Por exemplo, a barra de título do meu aplicativo é renderizada nítida e clara.

Boris
fonte

Respostas:

131

Depois de passar de 100% (ou 125% com a caixa de seleção "Escala de DPI no estilo XP" marcada), o Windows assume por padrão o escalonamento de sua IU. Ele faz isso fazendo com que seu aplicativo renderize sua saída em um bitmap e desenhe esse bitmap na tela. O redimensionamento desse bitmap torna o texto inevitavelmente confuso. Um recurso chamado "virtualização de DPI", ele mantém programas antigos utilizáveis ​​em monitores de alta resolução.

Você deve informar explicitamente que você pode lidar com configurações de DPI mais altas adicionando o <dpiAware>elemento ao seu manifesto. A página do MSDN está aqui, mas não está completa, pois está omitindo as configurações do UAC. Projeto + Adicionar Novo Item, escolha "Arquivo de Manifesto do Aplicativo". Edite o texto do manifesto ou copie / cole:

<?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>

Você também pode selecionar SetProcessDPIAware () em seu método Main (), necessário, por exemplo, se você implantar com 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();

ATUALIZAÇÃO, esta necessidade comum é finalmente um pouco mais fácil se você usar o VS2015 Atualização 1 ou superior. O manifesto adicionado já possui a diretiva relevante, basta remover os comentários.


Palavra-chave para pesquisa para que eu possa encontrar este post de volta: dpiAware

Hans Passant
fonte
Obrigado, sua solução funciona bem. O único problema que resta é que todas as imagens estão em seus tamanhos originais. Acho que terei que encontrar uma maneira de adicionar ícones de "retina" adicionais à minha GUI ...
Boris
@HansPassant Tenho o mesmo problema com fontes borradas e, depois de aplicar esta solução, meus controles não são redimensionados e não cabem. Como fazer os dois funcionarem?
gajo357
2
Para qualquer um que esteja investigando esta loucura do Win8, SetProcessDPIAwareestá obsoleto e também não funciona corretamente (pelo menos não no Win8.1), causando dimensionamento imprevisível em diferentes controles. Eu recomendo fortemente usar a abordagem de manifesto.
Jason Williams
5
Hmya, Windows 8.1 adquiriu DPI por monitor. Eu não sabia que precisava disso.
Hans Passant
1
Se você for usar ClickOnce para implantação, não poderá usar a opção dpiAware no manifesto, use SetProcessDPIAware ().
Matías
17

Os aplicativos podem ser desenvolvidos em dois modos diferentes.

A primeira é declarar que nosso aplicativo não reconhece DPI (não declarar nada será o padrão para isso). Nesse caso, o sistema operacional renderizará nosso aplicativo com os 96 DPI esperados e, em seguida, fará a escala de bitmap que discutimos antes. O resultado será um aplicativo embaçado, mas com um layout correto.

A segunda opção é declarar o aplicativo com reconhecimento de DPI. Nesse caso, o sistema operacional não fará nenhuma escala e permitirá que seu aplicativo seja renderizado de acordo com o DPI original da tela. No caso de um ambiente de DPI por monitor, seu aplicativo será renderizado com o DPI mais alto de todas as telas, então este bitmap será reduzido para o tamanho adequado para cada monitor. O downscaling resulta em uma experiência de visualização melhor do que o upscaling, mas você ainda pode notar alguma imprecisão.

Se quiser evitar isso, você deve declarar sua aplicação como compatível com o DPI do monitor. Em seguida, você deve detectar quando seu aplicativo é arrastado por monitores diferentes e renderizar de acordo com o DPI do atual.

A declaração do reconhecimento de DPI é feita em um arquivo de manifesto.

consulte o seguinte link stackoverflow

Shanthi_karthika
fonte
e se os usuários tiverem uma janela no tamanho restaurado e movê-la de forma que partes dela fiquem em monitores diferentes? precisamos renderizar tudo duas vezes e usar os limites do monitor como caixas delimitadoras? quanto disso é coberto pelas bibliotecas winforms?
Cee McSharpface,
4

Usando o .NET Framework 4.7 e o Windows 10 Creators Update (1703) ou mais recente, você deve fazer o seguinte para configurar o suporte a alto DPI para seu aplicativo Windows Form:

Declare compatibilidade com o Windows 10.

Para fazer isso, adicione o seguinte ao seu manifestarquivo:

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

Habilite o reconhecimento de DPI por monitor no app.configarquivo.

O Windows Forms apresenta um novo elemento System.Windows.Forms.ApplicationConfigurationSection para oferecer suporte a novos recursos e personalizações adicionados a partir do .NET Framework 4.7. Para aproveitar as vantagens dos novos recursos que oferecem suporte a alta DPI, adicione o seguinte ao arquivo de configuração do seu aplicativo.

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

Importante

Nas versões anteriores do .NET Framework, você usava o manifesto para adicionar suporte a alto DPI. Essa abordagem não é mais recomendada, pois substitui as configurações definidas no arquivo app.config.

Chame o método estático EnableVisualStyles.

Esta deve ser a primeira chamada de método em seu ponto de entrada do aplicativo. Por exemplo:

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

A vantagem disso é o suporte para cenários de DPI dinâmicos nos quais o usuário altera o DPI ou o fator de escala depois que um aplicativo Windows Forms foi iniciado.

Fonte: Suporte a alta DPI em Windows Forms

Wollmich
fonte
3

Nenhuma dessas sugestões funcionou para mim, mas, algo aconteceu depois que eu removi o Form.Font = new... do Form.Design.cs, o formulário começou a ser redimensionado corretamente, funciona se a fonte está definida no construtor ou não. Por quê? outra pessoa pode explicar, só posso falar sobre a alteração que fiz e levei alguns minutos para descobrir que era a causa raiz do formulário em que estava trabalhando. Espero que ajude.

Vasco Bonilla
fonte
2

Desde pelo menos o Visual Studio 2017, você só precisa adicionar um arquivo de manifesto e descomentar esta seção:

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