วิธีกำหนดค่าแอปให้ทำงานอย่างถูกต้องบนเครื่องด้วยการตั้งค่า DPI สูง (เช่น 150%)


104

ฉันได้สร้างแอปพลิเคชัน Winforms อย่างง่ายใน C # เมื่อฉันเรียกใช้แอปพลิเคชันบนเครื่องที่มีการตั้งค่า DPI สูง (เช่น 150%) แอปพลิเคชันจะถูกปรับขนาดขึ้น จนถึงตอนนี้ดีมาก! แต่แทนที่จะแสดงแบบอักษรที่มีขนาดตัวอักษรที่สูงขึ้นข้อความทั้งหมดจะถูกปรับขนาดให้ใหญ่ขึ้นด้วยเช่นกัน แน่นอนว่านำไปสู่ข้อความที่พร่ามัวมาก (บนตัวควบคุมทั้งหมดเช่นปุ่ม ฯลฯ )

windows ไม่ควรดูแลการแสดงผลข้อความอย่างถูกต้อง? ตัวอย่างเช่นแถบหัวเรื่องของแอปพลิเคชันของฉันแสดงผลที่คมชัดและชัดเจน

คำตอบ:


132

เมื่อคุณทำเกิน 100% (หรือ 125% โดยเลือกช่องทำเครื่องหมาย "การปรับขนาด DPI สไตล์ XP") โดยค่าเริ่มต้น Windows จะเข้าควบคุมการปรับขนาด UI ของคุณ ทำได้โดยให้แอปของคุณแสดงผลลัพธ์เป็นบิตแมปและวาดบิตแมปนั้นบนหน้าจอ การปรับขนาดของบิตแมปนั้นทำให้ข้อความดูไม่ชัดเจนอย่างหลีกเลี่ยงไม่ได้ คุณลักษณะที่เรียกว่า "DPI virtualization" ช่วยให้โปรแกรมเก่าสามารถใช้งานได้บนจอภาพความละเอียดสูง

คุณต้องแจ้งให้ทราบอย่างชัดเจนว่าคุณสามารถจัดการการตั้งค่า DPI ที่สูงขึ้นได้โดยการเพิ่ม<dpiAware>องค์ประกอบลงในไฟล์ Manifest ของคุณ หน้า MSDN อยู่ที่นี่แต่ยังไม่สมบูรณ์เนื่องจากไม่มีการตั้งค่า UAC โครงการ + เพิ่มรายการใหม่เลือก "ไฟล์รายการแอปพลิเคชัน" แก้ไขข้อความในรายการหรือคัดลอก / วางสิ่งนี้:

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

คุณยังสามารถปักหมุด SetProcessDPIAware () ในเมธอด Main () ของคุณได้เช่นหากคุณปรับใช้กับ 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();

อัปเดตความต้องการทั่วไปนี้จะง่ายขึ้นเล็กน้อยหากคุณใช้ VS2015 Update 1 หรือสูงกว่า ไฟล์ Manifest ที่เพิ่มมีคำสั่งที่เกี่ยวข้องอยู่แล้วเพียงแค่ลบความคิดเห็น


คีย์เวิร์ดสำหรับการค้นหาเพื่อให้ฉันสามารถค้นหาโพสต์นี้ได้: dpiAware


ขอบคุณโซลูชันของคุณใช้งานได้ดี ปัญหาเดียวที่เหลือคือตอนนี้ภาพทั้งหมดมีขนาดดั้งเดิมแล้ว ฉันเดาว่าฉันต้องหาวิธีเพิ่มไอคอน "เรตินา" เพิ่มเติมให้กับ GUI ของฉัน ...
บอริส

@HansPassant ฉันมีปัญหาเดียวกันกับฟอนต์พร่ามัวและหลังจากใช้โซลูชันนี้ตัวควบคุมของฉันไม่ปรับขนาดและไม่พอดี จะให้ทั้งสองทำงานได้อย่างไร?
gajo357

2
สำหรับใครก็ตามที่กำลังตรวจสอบความบ้าคลั่งของ Win8 นี้SetProcessDPIAwareจะถูกเลิกใช้งานและยังทำงานไม่ถูกต้อง (อย่างน้อยก็ไม่ใช่ใน Win8.1) ทำให้ไม่สามารถคาดเดาได้ในการควบคุมที่แตกต่างกัน ฉันขอแนะนำอย่างยิ่งให้ใช้วิธีการแสดงรายการแทน
Jason Williams

5
Hmya, Windows 8.1 ได้รับ DPI ต่อจอภาพ ฉันไม่รู้ว่าฉันต้องการสิ่งนั้น
Hans Passant

1
หากคุณจะใช้ ClickOnce ในการปรับใช้คุณไม่สามารถใช้ตัวเลือก dpiAware ในไฟล์ Manifest ให้ใช้ SetProcessDPIAware () แทน
Matías

17

แอพพลิเคชั่นสามารถพัฒนาได้ในสองโหมดที่แตกต่างกัน

สิ่งแรกคือการประกาศว่าแอปพลิเคชันของเราไม่รับรู้ DPI (การไม่แจ้งว่าสิ่งใดจะเป็นค่าเริ่มต้น) ในกรณีนี้ระบบปฏิบัติการจะแสดงแอปพลิเคชันของเราภายใต้96 DPI ที่คาดไว้จากนั้นจะทำการปรับขนาดบิตแมปที่เราพูดถึงก่อนหน้านี้ ผลลัพธ์จะเป็นแอปพลิเคชั่นที่ดูไม่ชัด แต่มีเค้าโครงที่ถูกต้อง

ตัวเลือกที่สองคือการประกาศแอปพลิเคชันเป็น DPI-awareness ในกรณีนี้ระบบปฏิบัติการจะไม่ทำการปรับขนาดใด ๆ และจะปล่อยให้แอปพลิเคชันของคุณแสดงผลตาม DPI ดั้งเดิมของหน้าจอ ในกรณีของสภาพแวดล้อมต่อจอภาพ -DPI แอปพลิเคชันของคุณจะแสดงผลด้วย DPI สูงสุดของหน้าจอทั้งหมดจากนั้นบิตแมปนี้จะถูกลดขนาดลงเป็นขนาดที่เหมาะสมสำหรับแต่ละจอภาพ การลดขนาดจะให้ประสบการณ์การรับชมที่ดีกว่าการลดขนาด แต่คุณอาจยังสังเกตเห็นความไม่ชัดเจนอยู่บ้าง

หากคุณต้องการหลีกเลี่ยงสิ่งนั้นคุณต้องประกาศแอปพลิเคชันของคุณตามจอภาพ DPI-Awareness จากนั้นคุณจะต้องตรวจจับเมื่อแอปพลิเคชันของคุณลากไปบนจอภาพต่างๆและแสดงผลตาม DPI ของจอภาพปัจจุบัน

การประกาศการรับรู้ DPI ทำได้ในไฟล์รายการ

อ้างอิงลิงค์ต่อไปนี้ stackoverflow


จะเกิดอะไรขึ้นถ้าผู้ใช้มีหน้าต่างในขนาดที่คืนค่าและย้ายเพื่อให้บางส่วนอยู่บนจอภาพที่ต่างกัน เราจำเป็นต้องแสดงผลทุกอย่างสองครั้งและใช้ขอบเขตจอภาพเป็นกรอบหรือไม่? ไลบรารี winforms ครอบคลุมเท่าใด
Cee McSharpface

5

การใช้. NET Framework 4.7 และ Windows 10 Creators Update (1703) หรือใหม่กว่าคุณต้องทำสิ่งต่อไปนี้เพื่อกำหนดค่าการสนับสนุน DPI สูงสำหรับแอปพลิเคชัน Windows Form ของคุณ:

ประกาศความเข้ากันได้กับ Windows 10

ในการดำเนินการนี้ให้เพิ่มสิ่งต่อไปนี้ในmanifestไฟล์ของคุณ:

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

เปิดใช้งานการรับรู้ DPI ต่อจอภาพในapp.configไฟล์

Windows Forms แนะนำองค์ประกอบSystem.Windows.Forms.ApplicationConfigurationSectionใหม่เพื่อรองรับคุณลักษณะใหม่และการปรับแต่งที่เพิ่มเข้ามาโดยเริ่มจาก. NET Framework 4.7 หากต้องการใช้ประโยชน์จากคุณสมบัติใหม่ที่รองรับ DPI สูงให้เพิ่มสิ่งต่อไปนี้ในไฟล์คอนฟิกูเรชันแอปพลิเคชันของคุณ

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

สิ่งสำคัญ

ในเวอร์ชันก่อนหน้าของ. NET Framework คุณใช้รายการเพื่อเพิ่มการสนับสนุน DPI สูง ไม่แนะนำให้ใช้วิธีนี้อีกต่อไปเนื่องจากจะลบล้างการตั้งค่าที่กำหนดไว้ในไฟล์ app.config

เรียกใช้เมธอด EnableVisualStyles แบบคงที่

นี่ควรเป็นการเรียกวิธีแรกในจุดเข้าแอปพลิเคชันของคุณ ตัวอย่างเช่น:

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

ข้อดีของสิ่งนี้คือการสนับสนุนสำหรับสถานการณ์ DPI แบบไดนามิกซึ่งผู้ใช้เปลี่ยน DPI หรือสเกลแฟคเตอร์หลังจากเปิดแอปพลิเคชัน Windows Forms

ที่มา: รองรับ DPI สูงใน Windows Forms


3

คำแนะนำเหล่านี้ไม่ได้ผลสำหรับฉัน แต่มีบางอย่างเกิดขึ้นหลังจากที่ฉันลบForm.Font = new... ออกจากForm.Design.csแบบฟอร์มเริ่มปรับขนาดใหม่อย่างถูกต้องจะใช้งานได้ถ้าฟอนต์ถูกกำหนดในตัวสร้างหรือไม่เลย ทำไม? คนอื่นอาจจะอธิบายได้ฉันสามารถพูดคุยเกี่ยวกับการเปลี่ยนแปลงที่ฉันทำและใช้เวลาสองสามนาทีเพื่อหาสาเหตุที่แท้จริงของแบบฟอร์มที่ฉันกำลังทำอยู่ หวังว่าจะช่วยได้


3

ตั้งแต่อย่างน้อย Visual Studio 2017 คุณต้องเพิ่มไฟล์ manifest และยกเลิกการแสดงความคิดเห็นในส่วนนี้:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
</application>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.