Bagaimana cara mengkonfigurasi aplikasi agar berjalan dengan benar pada mesin dengan pengaturan DPI tinggi (misalnya 150%)?


101

Saya telah membuat aplikasi Winforms sederhana di C #. Ketika saya menjalankan aplikasi pada mesin dengan pengaturan DPI tinggi (misalnya 150%), aplikasi akan ditingkatkan. Sejauh ini baik! Tetapi alih-alih merender font dengan ukuran font yang lebih tinggi, semua teks juga ditingkatkan. Itu tentu saja mengarah ke teks yang sangat buram (pada semua kontrol seperti tombol, dll.).

Bukankah windows harus menangani rendering teks dengan benar? Misalnya bilah judul aplikasi saya ditampilkan dengan jelas & tajam.

Jawaban:


131

Setelah Anda melewati 100% (atau 125% dengan kotak centang "XP-style DPI scaling" dicentang), Windows secara default mengambil alih penskalaan UI Anda. Itu dilakukan dengan meminta aplikasi Anda merender outputnya ke bitmap dan menggambar bitmap itu ke layar. Penskalaan bitmap tersebut membuat teks pasti terlihat kabur. Fitur yang disebut "virtualisasi DPI", membuat program lama tetap dapat digunakan pada monitor resolusi tinggi.

Anda harus secara eksplisit memberi tahu bahwa Anda dapat menangani pengaturan DPI yang lebih tinggi dengan menambahkan <dpiAware>elemen ke manifes Anda. Halaman MSDN ada di sini tetapi belum lengkap karena mengabaikan pengaturan UAC. Proyek + Tambahkan Item Baru, pilih "File Manifes Aplikasi". Edit teks manifes atau salin / tempel ini:

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

Anda juga dapat menyematkan SetProcessDPIAware () dalam metode Main () Anda, diperlukan misalnya jika Anda menerapkan dengan 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, kebutuhan umum ini akhirnya sedikit lebih mudah jika Anda menggunakan VS2015 Update 1 atau lebih tinggi. Manifes yang ditambahkan sudah memiliki petunjuk yang relevan, cukup hapus komentarnya.


Kata kunci untuk pencarian sehingga saya dapat menemukan posting ini kembali: dpiAware


Terima kasih, solusi Anda berfungsi dengan baik. Satu-satunya masalah yang tersisa adalah semua gambar sekarang dalam ukuran aslinya. Saya rasa saya harus menemukan cara untuk menambahkan ikon "retina" tambahan ke GUI saya ...
Boris

@HansPassant Saya memiliki masalah yang sama dengan font buram, dan setelah menerapkan solusi ini, kontrol saya tidak berskala dan tidak bisa pas. Bagaimana cara membuat keduanya bekerja?
gajo357

2
Bagi siapa pun yang menyelidiki kegilaan Win8 ini, SetProcessDPIAwaresudah usang, dan itu juga tidak berfungsi dengan baik (setidaknya tidak di Win8.1), menyebabkan penskalaan yang tidak dapat diprediksi pada kontrol yang berbeda. Saya sangat menyarankan menggunakan pendekatan manifes.
Jason Williams

5
Hmya, Windows 8.1 memperoleh DPI per monitor. Saya tidak sadar bahwa saya membutuhkannya.
Hans Passant

1
Jika Anda akan menggunakan ClickOnce untuk penyebaran, Anda tidak dapat menggunakan opsi dpiAware dalam manifes, gunakan SetProcessDPIAware () sebagai gantinya.
Matías

17

Aplikasi dapat dikembangkan dalam dua mode berbeda.

Yang pertama adalah mendeklarasikan aplikasi kita menjadi non-DPI-aware (tidak mendeklarasikan apapun yang akan default untuk ini). Dalam hal ini sistem operasi akan membuat aplikasi kita di bawah 96 DPI yang diharapkan dan kemudian akan melakukan penskalaan bitmap yang telah kita bahas sebelumnya. Hasilnya akan menjadi aplikasi yang tampak buram, tetapi dengan tata letak yang benar.

Opsi kedua adalah mendeklarasikan aplikasi sebagai DPI-aware. Dalam hal ini OS tidak akan melakukan penskalaan apa pun dan akan membiarkan aplikasi Anda merender sesuai dengan DPI asli layar. Dalam kasus lingkungan per-monitor-DPI, aplikasi Anda akan dirender dengan DPI tertinggi dari semua layar, kemudian bitmap ini akan diperkecil ke ukuran yang sesuai untuk setiap monitor. Penurunan skala menghasilkan pengalaman menonton yang lebih baik daripada peningkatan tetapi Anda mungkin masih melihat ketidakjelasan.

Jika Anda ingin menghindarinya, Anda harus mendeklarasikan aplikasi Anda sebagai per-monitor-DPI-aware. Kemudian Anda harus mendeteksi ketika aplikasi Anda diseret melintasi monitor yang berbeda dan merender sesuai dengan DPI yang sekarang.

Mendeklarasikan kesadaran DPI dilakukan dalam file manifes.

lihat link stackoverflow berikut


bagaimana jika pengguna memiliki jendela dalam ukuran yang dipulihkan dan memindahkannya sehingga bagian-bagiannya ada di monitor yang berbeda? apakah kita perlu merender semuanya dua kali dan menggunakan batas monitor sebagai kotak pembatas? berapa banyak yang dicakup oleh perpustakaan winforms?
Cee McSharpface

4

Menggunakan .NET Framework 4.7 dan Pembaruan Pembuat Windows 10 (1703) atau yang lebih baru, Anda harus melakukan hal-hal berikut untuk mengonfigurasi dukungan DPI tinggi untuk aplikasi Formulir Windows Anda:

Nyatakan kompatibilitas dengan Windows 10.

Untuk melakukan ini, tambahkan yang berikut ini ke manifest file :

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

Aktifkan kesadaran DPI per monitor di app.config file.

Formulir Windows memperkenalkan elemen System.Windows.Forms.ApplicationConfigurationSection baru untuk mendukung fitur baru dan kustomisasi yang ditambahkan dimulai dengan .NET Framework 4.7. Untuk memanfaatkan fitur baru yang mendukung DPI tinggi, tambahkan berikut ini ke file konfigurasi aplikasi Anda.

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

Penting

Di versi .NET Framework sebelumnya, Anda menggunakan manifes untuk menambahkan dukungan DPI tinggi. Pendekatan ini tidak lagi direkomendasikan, karena menggantikan pengaturan yang ditentukan pada file app.config.

Panggil metode EnableVisualStyles statis.

Ini harus menjadi pemanggilan metode pertama di titik masuk aplikasi Anda. Sebagai contoh:

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

Keuntungan ini adalah dukungan untuk skenario DPI dinamis di mana pengguna mengubah DPI atau faktor skala setelah aplikasi Windows Forms diluncurkan.

Sumber: Dukungan DPI tinggi di Windows Forms


3

Tak satu pun dari saran ini berhasil untuk saya tetapi, sesuatu terjadi setelah saya menghapus Form.Font = new... dari Form.Design.cs, formulir mulai menskalakan ulang dengan benar, ini berfungsi jika Font ditentukan dalam konstruktor atau tidak sama sekali. Mengapa? orang lain mungkin dapat menjelaskan, saya hanya dapat berbicara tentang perubahan yang saya buat dan membutuhkan waktu beberapa menit untuk mengetahui bahwa itu adalah akar penyebab formulir yang saya kerjakan. Semoga membantu.


2

Karena setidaknya Visual Studio 2017 Anda hanya perlu menambahkan file manifes dan hapus komentar di bagian ini:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
</application>
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.