¿Cómo configurar una aplicación para que se ejecute correctamente en una máquina con una configuración alta de DPI (por ejemplo, 150%)?

101

Creé una aplicación Winforms simple en C #. Cuando ejecuto la aplicación en una máquina con una configuración de PPP alta (por ejemplo, 150%), la aplicación se amplía. ¡Hasta aquí todo bien! Pero en lugar de representar las fuentes con un tamaño de fuente mayor, todos los textos también se amplían. Eso, por supuesto, conduce a un texto muy borroso (en todos los controles como botones, etc.).

¿No debería Windows encargarse de reproducir los textos correctamente? Por ejemplo, la barra de título de mi aplicación se muestra nítida y clara.

Boris
fuente

Respuestas:

131

Una vez que supere el 100% (o el 125% con la casilla de verificación "Escala de DPI al estilo XP" marcada), Windows se hace cargo de forma predeterminada de la escala de su interfaz de usuario. Lo hace haciendo que su aplicación represente su salida en un mapa de bits y dibuje ese mapa de bits en la pantalla. El cambio de escala de ese mapa de bits hace que el texto se vea inevitablemente borroso. Una característica llamada "virtualización DPI", mantiene los programas antiguos utilizables en monitores de alta resolución.

Debe hacerle saber explícitamente que puede manejar configuraciones de DPI más altas agregando el <dpiAware>elemento a su manifiesto. La página de MSDN está aquí, pero no está completa porque omite la configuración de UAC. Proyecto + Agregar nuevo elemento, seleccione "Archivo de manifiesto de aplicación". Edite el texto del manifiesto o copie / pegue esto:

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

También puede pinvoke SetProcessDPIAware () en su método Main (), necesario, por ejemplo, si implementa con 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();

ACTUALIZAR, esta necesidad común es finalmente un poco más fácil si usa VS2015 Update 1 o superior. El manifiesto agregado ya tiene la directiva relevante, simplemente elimine los comentarios.


Palabra clave para buscar para poder encontrar esta publicación: dpiAware

Hans Passant
fuente
Gracias, tu solución funciona bien. El único problema que queda es que todas las imágenes están ahora en sus tamaños originales. Supongo que tendré que encontrar una manera de agregar iconos de "retina" adicionales a mi GUI ...
Boris
@HansPassant Tengo el mismo problema con las fuentes borrosas y, después de aplicar esta solución, mis controles no se escalan y no caben. ¿Cómo hacer que ambos funcionen?
gajo357
2
Para cualquiera que esté investigando esta locura de Win8, SetProcessDPIAwareestá en desuso y tampoco funciona correctamente (al menos no en Win8.1), lo que provoca un escalado impredecible en diferentes controles. Recomiendo encarecidamente utilizar el enfoque de manifiesto en su lugar.
Jason Williams
5
Hmya, Windows 8.1 adquirió DPI por monitor. No sabía que necesitaba eso.
Hans Passant
1
Si va a utilizar ClickOnce para la implementación, no puede utilizar la opción dpiAware en el manifiesto, utilice SetProcessDPIAware () en su lugar.
Matías
17

Las aplicaciones se pueden desarrollar de dos modos diferentes.

El primero es declarar que nuestra aplicación no es compatible con DPI (no declarar nada será predeterminado). En este caso, el sistema operativo renderizará nuestra aplicación bajo los 96 DPI esperados y luego lo hará con la escala de mapa de bits que discutimos antes. El resultado será una aplicación de aspecto borroso, pero con un diseño correcto.

La segunda opción es declarar la aplicación como compatible con DPI. En este caso, el sistema operativo no escalará y permitirá que su aplicación se procese de acuerdo con el DPI original de la pantalla. En el caso de un entorno de DPI por monitor, su aplicación se renderizará con el DPI más alto de todas las pantallas, luego este mapa de bits se reducirá al tamaño adecuado para cada monitor. La reducción de escala da como resultado una mejor experiencia de visualización que la ampliación de escala, pero es posible que aún note algo de confusión.

Si desea evitar eso, debe declarar su aplicación como compatible con DPI por monitor. Luego debes detectar cuando tu aplicación es arrastrada por diferentes monitores y renderizar de acuerdo al DPI del actual.

La declaración del reconocimiento de DPI se realiza en un archivo de manifiesto.

consulte el siguiente enlace stackoverflow

shanthi_karthika
fuente
¿Qué pasa si los usuarios tienen una ventana en tamaño restaurado y la mueven para que partes de ella estén en diferentes monitores? ¿Necesitamos renderizar todo dos veces y usar los límites del monitor como cuadros delimitadores? ¿Cuánto de eso está cubierto por las bibliotecas winforms?
Cee McSharpface
4

Con .NET Framework 4.7 y Windows 10 Creators Update (1703) o más reciente, debe hacer lo siguiente para configurar el soporte de alto DPI para su aplicación de Windows Form:

Declare compatibilidad con Windows 10.

Para hacer esto, agregue lo siguiente a su manifestarchivo:

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

Habilite el reconocimiento de DPI por monitor en el app.configarchivo.

Windows Forms presenta un nuevo elemento System.Windows.Forms.ApplicationConfigurationSection para admitir nuevas características y personalizaciones agregadas a partir de .NET Framework 4.7. Para aprovechar las nuevas funciones que admiten un DPI alto, agregue lo siguiente al archivo de configuración de su aplicación.

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

Importante

En versiones anteriores de .NET Framework, usó el manifiesto para agregar compatibilidad alta con DPI. Este enfoque ya no se recomienda, ya que anula la configuración definida en el archivo app.config.

Llame al método estático EnableVisualStyles.

Esta debería ser la primera llamada al método en el punto de entrada de su aplicación. Por ejemplo:

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

La ventaja de esto es la compatibilidad con escenarios dinámicos de PPP en los que el usuario cambia el PPP o el factor de escala después de que se haya lanzado una aplicación de Windows Forms.

Fuente: soporte de alto DPI en Windows Forms

Wollmich
fuente
3

Ninguna de estas sugerencias funcionó para mí, pero algo sucedió después de que eliminé el Form.Font = new... del Form.Design.cs, el formulario comenzó a escalar correctamente, funciona si la fuente está definida en el constructor o no. ¿Por qué? alguien más podría explicarme, solo puedo hablar sobre el cambio que hice y me tomó unos minutos descubrir que era la causa raíz del formulario en el que estaba trabajando. Espero eso ayude.

Vasco Bonilla
fuente
2

Desde al menos Visual Studio 2017, solo tiene que agregar un archivo de manifiesto y descomentar esta sección:

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