Wie konfiguriere ich eine App so, dass sie auf einem Computer mit einer hohen DPI-Einstellung (z. B. 150%) korrekt ausgeführt wird?

101

Ich habe eine einfache Winforms-Anwendung in C # erstellt. Wenn ich die Anwendung auf einem Computer mit hohen DPI-Einstellungen (z. B. 150%) ausführe, wird die Anwendung vergrößert. So weit, ist es gut! Anstatt die Schriftarten mit einer höheren Schriftgröße zu rendern, werden auch alle Texte nur vergrößert. Das führt natürlich zu sehr verschwommenem Text (auf allen Steuerelementen wie Schaltflächen usw.).

Sollte Windows nicht dafür sorgen, dass die Texte korrekt gerendert werden? Zum Beispiel wird die Titelleiste meiner Anwendung klar und deutlich dargestellt.

Boris
quelle

Antworten:

131

Sobald Sie 100% überschritten haben (oder 125%, wenn das Kontrollkästchen "DPI-Skalierung im XP-Stil" aktiviert ist), übernimmt Windows standardmäßig die Skalierung Ihrer Benutzeroberfläche. Dazu wird Ihre App die Ausgabe in eine Bitmap rendern und diese Bitmap auf den Bildschirm zeichnen. Durch die Neuskalierung dieser Bitmap sieht der Text unweigerlich unscharf aus. Eine Funktion namens "DPI-Virtualisierung", mit der alte Programme auf hochauflösenden Monitoren verwendet werden können.

Sie müssen ausdrücklich darauf hinweisen, dass Sie mit höheren DPI-Einstellungen umgehen können, indem Sie das <dpiAware>Element zu Ihrem Manifest hinzufügen . Die MSDN-Seite ist hier, aber nicht vollständig, da die UAC-Einstellungen weggelassen werden. Projekt + Neues Element hinzufügen, wählen Sie "Anwendungsmanifestdatei". Bearbeiten Sie den Manifesttext oder kopieren / fügen Sie Folgendes ein:

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

Sie können SetProcessDPIAware () auch in Ihrer Main () -Methode aufrufen, z. B. wenn Sie mit ClickOnce bereitstellen:

    [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, diese häufige Anforderung ist endlich etwas einfacher, wenn Sie VS2015 Update 1 oder höher verwenden. Das hinzugefügte Manifest enthält bereits die entsprechende Anweisung. Entfernen Sie einfach die Kommentare.


Stichwort für die Suche, damit ich diesen Beitrag wiederfinden kann: dpiAware

Hans Passant
quelle
Vielen Dank, Ihre Lösung funktioniert gut. Das einzige verbleibende Problem ist, dass alle Bilder jetzt ihre Originalgröße haben. Ich denke, ich muss einen Weg finden, um zusätzliche "Retina" -ikons zu meiner GUI hinzuzufügen ...
Boris
@HansPassant Ich habe das gleiche Problem mit verschwommenen Schriftarten. Nach dem Anwenden dieser Lösung skalieren meine Steuerelemente nicht und passen nicht. Wie bringt man beide zur Arbeit?
Gajo357
2
Jeder, der diesen Win8-Wahnsinn untersucht, SetProcessDPIAwareist veraltet und funktioniert auch nicht richtig (zumindest nicht in Win8.1), was zu einer unvorhersehbaren Skalierung auf verschiedenen Steuerelementen führt. Ich empfehle dringend, stattdessen den Manifest-Ansatz zu verwenden.
Jason Williams
5
Hmya, Windows 8.1 hat DPI pro Monitor erworben. Mir war nicht bewusst, dass ich das brauchte.
Hans Passant
1
Wenn Sie ClickOnce für die Bereitstellung verwenden möchten, können Sie die Option dpiAware nicht im Manifest verwenden. Verwenden Sie stattdessen SetProcessDPIAware ().
Matías
17

Anwendungen können in zwei verschiedenen Modi entwickelt werden.

Die erste besteht darin, unsere Anwendung als nicht DPI-fähig zu deklarieren (dies wird standardmäßig nicht deklariert). In diesem Fall rendert das Betriebssystem unsere Anwendung unter den erwarteten 96 DPI und führt dann die zuvor beschriebene Bitmap-Skalierung durch. Das Ergebnis ist eine verschwommen aussehende Anwendung mit korrektem Layout.

Die zweite Möglichkeit besteht darin, die Anwendung als DPI-fähig zu deklarieren. In diesem Fall führt das Betriebssystem keine Skalierung durch und lässt Ihre Anwendung gemäß der ursprünglichen DPI des Bildschirms rendern. In einer Umgebung pro Monitor und DPI wird Ihre Anwendung mit der höchsten DPI aller Bildschirme gerendert. Anschließend wird diese Bitmap für jeden Monitor auf die richtige Größe verkleinert. Das Herunterskalieren führt zu einem besseren Seherlebnis als das Hochskalieren, aber Sie bemerken möglicherweise immer noch eine gewisse Unschärfe.

Wenn Sie dies vermeiden möchten, müssen Sie Ihre Anwendung als pro Monitor-DPI-fähig deklarieren. Dann müssen Sie erkennen, wann Ihre Anwendung über verschiedene Monitore gezogen und gemäß der DPI des aktuellen gerendert wird.

Das Deklarieren der DPI-Kenntnis erfolgt in einer Manifestdatei.

Verweisen Sie auf den folgenden Link- Stackoverflow

shanthi_karthika
quelle
Was ist, wenn Benutzer ein Fenster in wiederhergestellter Größe haben und es so verschieben, dass sich Teile davon auf verschiedenen Monitoren befinden? Müssen wir alles zweimal rendern und die Monitorgrenzen als Begrenzungsrahmen verwenden? Wie viel davon wird von den Winforms-Bibliotheken abgedeckt?
Cee McSharpface
4

Mit .NET Framework 4.7 und Windows 10 Creators Update (1703) oder neuer müssen Sie die folgenden Schritte ausführen, um die Unterstützung für hohe DPI-Werte für Ihre Windows Form-Anwendung zu konfigurieren:

Deklarieren Sie die Kompatibilität mit Windows 10.

Fügen Sie dazu Ihrer manifestDatei Folgendes hinzu :

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

Aktivieren Sie die DPI-Erkennung pro Monitor in der app.configDatei.

Windows Forms führt ein neues System.Windows.Forms.ApplicationConfigurationSection- Element ein, um neue Funktionen und Anpassungen zu unterstützen, die ab .NET Framework 4.7 hinzugefügt wurden. Fügen Sie Ihrer Anwendungskonfigurationsdatei Folgendes hinzu, um die neuen Funktionen zu nutzen, die hohe DPI unterstützen.

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

Wichtig

In früheren Versionen von .NET Framework haben Sie das Manifest verwendet, um Unterstützung für hohe DPI hinzuzufügen. Dieser Ansatz wird nicht mehr empfohlen, da er die in der Datei app.config definierten Einstellungen überschreibt.

Rufen Sie die statische EnableVisualStyles-Methode auf.

Dies sollte der erste Methodenaufruf in Ihrem Anwendungseinstiegspunkt sein. Beispielsweise:

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

Dies hat den Vorteil, dass dynamische DPI-Szenarien unterstützt werden, in denen der Benutzer den DPI- oder Skalierungsfaktor nach dem Start einer Windows Forms-Anwendung ändert.

Quelle: Unterstützung für hohe DPI in Windows Forms

Wollmich
quelle
3

Keiner dieser Vorschläge hat bei mir funktioniert, aber etwas ist passiert, nachdem ich das Form.Font = new... aus dem entfernt habe Form.Design.cs. Das Formular wurde ordnungsgemäß neu skaliert. Es funktioniert, wenn die Schriftart im Konstruktor definiert ist oder überhaupt nicht. Warum? Vielleicht kann jemand anderes erklären, ich kann nur über die Änderungen sprechen, die ich vorgenommen habe, und ich habe ein paar Minuten gebraucht, um herauszufinden, dass dies die Hauptursache für das Formular war, an dem ich gearbeitet habe. Ich hoffe es hilft.

Vasco Bonilla
quelle
2

Seit mindestens Visual Studio 2017 müssen Sie nur noch eine Manifestdatei hinzufügen und diesen Abschnitt auskommentieren:

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