Come configurare un'app per funzionare correttamente su una macchina con un'impostazione DPI alta (es. 150%)?


101

Ho creato una semplice applicazione Winforms in C #. Quando eseguo l'applicazione su una macchina con impostazioni DPI elevate (ad esempio 150%), l'applicazione viene ridimensionata. Fin qui tutto bene! Ma invece di rendere i caratteri con una dimensione del carattere maggiore, anche tutti i testi vengono ridimensionati. Ciò ovviamente porta a un testo molto sfocato (su tutti i controlli come pulsanti ecc.).

Windows non dovrebbe occuparsi di riprodurre correttamente i testi? Ad esempio, la barra del titolo della mia applicazione è resa nitida e chiara.

Risposte:


131

Una volta superato il 100% (o il 125% con la casella di controllo "Ridimensionamento DPI stile XP" selezionata), Windows assume per impostazione predefinita il ridimensionamento dell'interfaccia utente. Lo fa facendo in modo che la tua app effettui il rendering del suo output in una bitmap e disegnando quella bitmap sullo schermo. Il ridimensionamento di quella bitmap rende il testo inevitabilmente sfocato. Una funzionalità chiamata "virtualizzazione DPI", mantiene i vecchi programmi utilizzabili su monitor ad alta risoluzione.

Devi fargli sapere esplicitamente che puoi gestire impostazioni DPI più elevate aggiungendo l' <dpiAware>elemento al tuo manifest. La pagina MSDN è qui ma non è completa poiché omette le impostazioni dell'UAC. Progetto + Aggiungi nuovo elemento, seleziona "File manifest dell'applicazione". Modifica il testo manifest o copia / incolla questo:

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

Puoi anche pinvoke SetProcessDPIAware () nel tuo metodo Main (), necessario ad esempio se distribuisci 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();

AGGIORNAMENTO, questa esigenza comune è finalmente un po 'più semplice se usi VS2015 Update 1 o successivo. Il manifest aggiunto ha già la direttiva pertinente, è sufficiente rimuovere i commenti.


Parola chiave per la ricerca in modo da poter trovare questo post indietro: dpiAware


Grazie, la tua soluzione funziona bene. L'unico problema rimasto è che tutte le immagini ora hanno le dimensioni originali. Immagino che dovrò trovare un modo per aggiungere ulteriori icone "retina" alla mia GUI ...
Boris

@HansPassant Ho lo stesso problema con i caratteri sfocati e, dopo aver applicato questa soluzione, i miei controlli non vengono ridimensionati e non possono adattarsi. Come far funzionare entrambi?
gajo357

2
Per chiunque indaghi su questa follia di Win8, SetProcessDPIAwareè deprecato e inoltre non funziona correttamente (almeno non in Win8.1), causando un ridimensionamento imprevedibile su diversi controlli. Consiglio vivamente di utilizzare invece l'approccio manifest.
Jason Williams,

5
Hmya, Windows 8.1 ha acquisito DPI per monitor. Non sapevo di averne bisogno.
Hans Passant

1
Se si intende utilizzare ClickOnce per la distribuzione, non è possibile utilizzare l'opzione dpiAware in manifest, utilizzare invece SetProcessDPIAware ().
Matías

17

Le applicazioni possono essere sviluppate in due modalità differenti.

Il primo è dichiarare che la nostra applicazione non è a conoscenza di DPI (non dichiarare nulla verrà impostato per impostazione predefinita su questo). In questo caso il sistema operativo eseguirà il rendering della nostra applicazione sotto i 96 DPI previsti e quindi eseguirà il ridimensionamento della bitmap di cui abbiamo discusso prima. Il risultato sarà un'applicazione dall'aspetto sfocato, ma con un layout corretto.

La seconda opzione è dichiarare l'applicazione come compatibile con DPI. In questo caso il sistema operativo non eseguirà alcun ridimensionamento e consentirà il rendering dell'applicazione in base al DPI originale dello schermo. In caso di un ambiente DPI per monitor, l'applicazione verrà renderizzata con il DPI più alto di tutti gli schermi, quindi questa bitmap verrà ridimensionata alla dimensione corretta per ogni monitor. Il downscaling offre un'esperienza visiva migliore rispetto all'upscaling, ma potresti comunque notare un po 'di sfocatura.

Se vuoi evitarlo, devi dichiarare la tua applicazione come compatibile con DPI per monitor. Quindi devi rilevare quando la tua applicazione viene trascinata su diversi monitor ed eseguire il rendering in base al DPI di quello corrente.

La dichiarazione del riconoscimento DPI viene eseguita in un file manifest.

fare riferimento al seguente link stackoverflow


cosa succede se gli utenti hanno una finestra di dimensioni ripristinate e la spostano in modo che parti di essa siano su monitor diversi? dobbiamo renderizzare tutto due volte e usare i confini del monitor come riquadri di delimitazione? quanto di questo è coperto dalle librerie winforms?
Cee McSharpface

4

Utilizzando .NET Framework 4.7 e Windows 10 Creators Update (1703) o versioni successive, è necessario eseguire le operazioni seguenti per configurare il supporto DPI elevato per l'applicazione Windows Form:

Dichiara la compatibilità con Windows 10.

Per fare ciò, aggiungi quanto segue al tuo manifestfile:

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

Abilita il riconoscimento DPI per monitor nel app.configfile.

Windows Forms introduce un nuovo elemento System.Windows.Forms.ApplicationConfigurationSection per supportare nuove funzionalità e personalizzazioni aggiunte a partire da .NET Framework 4.7. Per sfruttare le nuove funzionalità che supportano DPI elevati, aggiungere quanto segue al file di configurazione dell'applicazione.

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

Importante

Nelle versioni precedenti di .NET Framework, utilizzavi il manifest per aggiungere il supporto per DPI elevati. Questo approccio non è più consigliato, poiché sovrascrive le impostazioni definite nel file app.config.

Chiama il metodo EnableVisualStyles statico.

Questa dovrebbe essere la prima chiamata al metodo nel punto di ingresso dell'applicazione. Per esempio:

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

Il vantaggio di ciò è il supporto per scenari DPI dinamici in cui l'utente modifica il DPI o il fattore di scala dopo l'avvio di un'applicazione Windows Forms.

Origine: supporto DPI elevato in Windows Form


3

Nessuno di questi suggerimenti ha funzionato per me ma, è successo qualcosa dopo aver rimosso Form.Font = new... da Form.Design.cs, il modulo ha iniziato a ridimensionarsi correttamente, funziona se il carattere è definito nel costruttore o non lo è affatto. Perché? qualcun altro potrebbe essere in grado di spiegarlo, posso solo parlare della modifica che ho fatto e mi ci sono voluti alcuni minuti per capire che era la causa principale del modulo su cui stavo lavorando. Spero che sia d'aiuto.


2

Dal momento che almeno Visual Studio 2017 devi solo aggiungere un file manifest e rimuovere il commento da questa sezione:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
</application>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.