Comment configurer une application pour qu'elle s'exécute correctement sur une machine avec un paramètre DPI élevé (par exemple 150%)?

104

J'ai créé une application Winforms simple en C #. Lorsque j'exécute l'application sur une machine avec des paramètres DPI élevés (par exemple 150%), l'application est mise à l'échelle. Jusqu'ici tout va bien! Mais au lieu de rendre les polices avec une taille de police plus élevée, tous les textes sont également mis à l'échelle. Cela conduit bien sûr à un texte très flou (sur tous les contrôles comme les boutons, etc.).

Windows ne devrait-il pas prendre soin de rendre les textes correctement? Par exemple, la barre de titre de mon application est rendue claire et nette.

Boris
la source

Réponses:

132

Une fois que vous dépassez les 100% (ou 125% avec la case à cocher "Mise à l'échelle PPP de style XP" cochée), Windows prend par défaut le contrôle de la mise à l'échelle de votre interface utilisateur. Pour ce faire, votre application affiche sa sortie sous forme de bitmap et dessine cette image à l'écran. Le redimensionnement de ce bitmap rend le texte inévitablement flou. Une fonctionnalité appelée «virtualisation DPI», elle permet de conserver les anciens programmes utilisables sur des moniteurs haute résolution.

Vous devez lui indiquer explicitement que vous pouvez gérer des paramètres DPI plus élevés en ajoutant l' <dpiAware>élément à votre manifeste. La page MSDN est ici mais elle n'est pas complète car elle omet les paramètres UAC. Projet + Ajouter un nouvel élément, choisissez "Fichier manifeste de l'application". Modifiez le texte du manifeste ou copiez / collez ceci:

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

Vous pouvez également pinvoke SetProcessDPIAware () dans votre méthode Main (), nécessaire par exemple si vous déployez avec 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();

UPDATE, ce besoin commun est enfin un peu plus facile si vous utilisez VS2015 Update 1 ou supérieur. Le manifeste ajouté contient déjà la directive correspondante, supprimez simplement les commentaires.


Mot-clé de recherche pour que je puisse retrouver ce message: dpiAware

Hans Passant
la source
Merci, votre solution fonctionne bien. Le seul problème qui reste est que toutes les images sont maintenant à leur taille d'origine. Je suppose que je vais devoir trouver un moyen d'ajouter des icônes "rétine" supplémentaires à mon interface graphique ...
Boris
@HansPassant J'ai le même problème avec les polices floues, et après avoir appliqué cette solution, mes contrôles ne sont pas mis à l'échelle et ils ne peuvent pas s'adapter. Comment faire fonctionner les deux?
gajo357
2
Pour quiconque enquête sur cette folie de Win8, SetProcessDPIAwareest obsolète, et cela ne fonctionne pas non plus correctement (du moins pas dans Win8.1), provoquant une mise à l'échelle imprévisible sur différents contrôles. Je recommande fortement d'utiliser plutôt l'approche manifeste.
Jason Williams
5
Hmya, Windows 8.1 a acquis le DPI par moniteur. Je ne savais pas que j'avais besoin de ça.
Hans Passant
1
Si vous prévoyez d'utiliser ClickOnce pour le déploiement, vous ne pouvez pas utiliser l'option dpiAware dans le manifeste, utilisez plutôt SetProcessDPIAware ().
Matías
17

Les applications peuvent être développées selon deux modes différents.

La première consiste à déclarer que notre application n'est pas compatible DPI (ne rien déclarer par défaut). Dans ce cas, le système d'exploitation rendra notre application sous les 96 DPI attendus , puis appliquera la mise à l'échelle bitmap dont nous avons parlé précédemment. Le résultat sera une application d'apparence floue, mais avec une mise en page correcte.

La deuxième option consiste à déclarer l'application comme compatible DPI. Dans ce cas, le système d'exploitation n'effectuera aucune mise à l'échelle et laissera votre application s'afficher en fonction du DPI d'origine de l'écran. Dans le cas d'un environnement PPP par moniteur, votre application sera rendue avec le DPI le plus élevé de tous les écrans, puis ce bitmap sera réduit à la taille appropriée pour chaque moniteur. La mise à l'échelle permet une meilleure expérience de visualisation que la mise à l'échelle, mais vous remarquerez peut-être encore un peu de flou.

Si vous souhaitez éviter cela, vous devez déclarer votre application comme compatible avec le moniteur DPI. Ensuite, vous devez détecter le moment où votre application est déplacée sur différents moniteurs et effectuer un rendu en fonction du DPI de celui en cours.

La déclaration de la reconnaissance DPI se fait dans un fichier manifeste.

reportez-vous au lien suivant stackoverflow

shanthi_karthika
la source
que se passe-t-il si les utilisateurs ont une fenêtre à la taille restaurée et la déplacent afin que certaines parties de celle-ci soient sur différents moniteurs? devons-nous tout rendre deux fois et utiliser les limites du moniteur comme cadres de délimitation? combien de cela est couvert par les bibliothèques winforms?
Cee McSharpface
4

À l'aide de .NET Framework 4.7 et de Windows 10 Creators Update (1703) ou version ultérieure, vous devez effectuer les opérations suivantes pour configurer la prise en charge de la résolution haute résolution pour votre application Windows Form:

Déclarez la compatibilité avec Windows 10.

Pour ce faire, ajoutez ce qui suit à votre manifestfichier:

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

Activez la reconnaissance DPI par moniteur dans le app.configfichier.

Windows Forms introduit un nouvel élément System.Windows.Forms.ApplicationConfigurationSection pour prendre en charge les nouvelles fonctionnalités et personnalisations ajoutées à partir de .NET Framework 4.7. Pour profiter des nouvelles fonctionnalités qui prennent en charge le DPI élevé, ajoutez les éléments suivants à votre fichier de configuration d'application.

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

Important

Dans les versions précédentes du .NET Framework, vous utilisiez le manifeste pour ajouter une prise en charge DPI élevée. Cette approche n'est plus recommandée, car elle remplace les paramètres définis dans le fichier app.config.

Appelez la méthode statique EnableVisualStyles.

Cela devrait être le premier appel de méthode dans le point d'entrée de votre application. Par exemple:

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

L'avantage de ceci est la prise en charge des scénarios DPI dynamiques dans lesquels l'utilisateur modifie le DPI ou le facteur d'échelle après le lancement d'une application Windows Forms.

Source: prise en charge de haute résolution dans Windows Forms

Wollmich
la source
3

Aucune de ces suggestions n'a fonctionné pour moi mais, quelque chose s'est passé après que j'ai supprimé le Form.Font = new... du Form.Design.cs, le formulaire a commencé à se redimensionner correctement, cela fonctionne si la police est définie dans le constructeur ou pas du tout. Pourquoi? quelqu'un d'autre pourra peut-être l'expliquer, je peux simplement parler du changement que j'ai fait et il m'a fallu quelques minutes pour comprendre que c'était la cause première du formulaire sur lequel je travaillais. J'espère que ça aide.

Vasco Bonilla
la source
2

Depuis au moins Visual Studio 2017, il vous suffit d'ajouter un fichier manifeste et de décommenter cette section:

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