Làm cách nào để định cấu hình ứng dụng chạy chính xác trên máy có cài đặt DPI cao (ví dụ: 150%)?


101

Tôi đã tạo một ứng dụng Winforms đơn giản trong C #. Khi tôi chạy ứng dụng trên máy có cài đặt DPI cao (ví dụ: 150%), ứng dụng sẽ được mở rộng. Càng xa càng tốt! Nhưng thay vì hiển thị các phông chữ với kích thước phông chữ cao hơn, tất cả các văn bản cũng chỉ được thu nhỏ. Điều đó tất nhiên dẫn đến văn bản rất mờ (trên tất cả các điều khiển như nút, v.v.).

Các cửa sổ không nên quan tâm đến việc hiển thị các văn bản một cách chính xác? Ví dụ: thanh tiêu đề của ứng dụng của tôi được hiển thị sắc nét và rõ ràng.

Câu trả lời:


131

Sau khi bạn vượt qua 100% (hoặc 125% với hộp kiểm "Tỷ lệ DPI kiểu XP" được chọn), Windows theo mặc định sẽ tiếp quản tỷ lệ giao diện người dùng của bạn. Nó làm như vậy bằng cách để ứng dụng của bạn hiển thị đầu ra của nó thành một bitmap và vẽ bitmap đó ra màn hình. Việc thay đổi tỷ lệ của bitmap đó làm cho văn bản chắc chắn trông mờ. Một tính năng được gọi là "ảo hóa DPI", nó giữ cho các chương trình cũ có thể sử dụng được trên màn hình có độ phân giải cao.

Bạn phải thông báo rõ ràng rằng bạn có thể xử lý các cài đặt DPI cao hơn bằng cách thêm <dpiAware>phần tử vào tệp kê khai của mình. Trang MSDN ở đây nhưng nó chưa hoàn chỉnh vì nó đang bỏ qua cài đặt UAC. Dự án + Thêm Mục mới, chọn "Tệp kê khai ứng dụng". Chỉnh sửa văn bản kê khai hoặc sao chép / dán cái này:

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

Bạn cũng có thể ghim SetProcessDPIAware () trong phương thức Main () của mình, cần thiết, chẳng hạn như nếu bạn triển khai với 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();

CẬP NHẬT, nhu cầu chung này cuối cùng cũng dễ dàng hơn một chút nếu bạn sử dụng VS2015 Update 1 hoặc cao hơn. Tệp kê khai được thêm vào đã có chỉ thị liên quan, chỉ cần xóa các nhận xét.


Từ khóa tìm kiếm để tôi có thể tìm lại bài đăng này: dpiAware


Cảm ơn, giải pháp của bạn hoạt động tốt. Vấn đề duy nhất còn lại là tất cả hình ảnh bây giờ ở kích thước ban đầu của chúng. Tôi đoán tôi sẽ phải tìm cách thêm các -icon "võng mạc" bổ sung vào GUI của mình ...
Boris

@HansPassant Tôi gặp vấn đề tương tự với phông chữ mờ và sau khi áp dụng giải pháp này, các điều khiển của tôi không mở rộng và chúng không thể vừa vặn. Làm thế nào để cả hai hoạt động?
gajo357

2
Đối với bất kỳ ai đang điều tra sự điên rồ này của Win8, SetProcessDPIAwarekhông được dùng nữa và nó cũng không hoạt động bình thường (ít nhất là không phải trong Win8.1), gây ra tỷ lệ không thể đoán trước trên các điều khiển khác nhau. Tôi thực sự khuyên bạn nên sử dụng cách tiếp cận tệp kê khai để thay thế.
Jason Williams

5
Hmya, Windows 8.1 có được DPI trên mỗi màn hình. Tôi không biết rằng tôi cần điều đó.
Hans Passant

1
Nếu bạn định sử dụng ClickOnce để triển khai, bạn không thể sử dụng tùy chọn dpiAware trong tệp kê khai, hãy sử dụng SetProcessDPIAware () để thay thế.
Matías

17

Các ứng dụng có thể được phát triển ở hai chế độ khác nhau.

Đầu tiên là khai báo ứng dụng của chúng ta là không nhận biết DPI (không khai báo bất kỳ điều gì sẽ mặc định là ứng dụng này). Trong trường hợp này, hệ điều hành sẽ hiển thị ứng dụng của chúng ta dưới 96 DPI dự kiến và sau đó sẽ thực hiện theo tỷ lệ bitmap mà chúng ta đã thảo luận trước đó. Kết quả sẽ là một ứng dụng trông mờ nhưng có bố cục chính xác.

Tùy chọn thứ hai là khai báo ứng dụng là nhận biết DPI. Trong trường hợp này, hệ điều hành sẽ không thực hiện bất kỳ tỷ lệ nào và sẽ cho phép ứng dụng của bạn hiển thị theo DPI ban đầu của màn hình. Trong trường hợp môi trường mỗi màn hình-DPI, ứng dụng của bạn sẽ được hiển thị với DPI cao nhất trong tất cả các màn hình, sau đó bitmap này sẽ được thu nhỏ lại thành kích thước phù hợp cho mỗi màn hình. Nâng cấp dẫn đến trải nghiệm xem tốt hơn nâng cấp nhưng bạn vẫn có thể nhận thấy một số điểm mờ.

Nếu bạn muốn tránh điều đó, bạn phải khai báo ứng dụng của mình là nhận biết theo từng màn hình-DPI. Sau đó, bạn phải phát hiện khi nào ứng dụng của bạn được kéo qua các màn hình khác nhau và hiển thị theo DPI của màn hình hiện tại.

Việc khai báo nhận thức về DPI được thực hiện trong một tệp kê khai.

tham khảo stackoverflow liên kết sau


Điều gì sẽ xảy ra nếu người dùng có một cửa sổ ở kích thước được khôi phục và di chuyển nó để các phần của nó nằm trên các màn hình khác nhau? chúng ta có cần phải kết xuất mọi thứ hai lần và sử dụng các ranh giới màn hình làm hộp giới hạn không? bao nhiêu trong số đó được bao phủ bởi các thư viện winforms?
Cee McSharpface,

4

Sử dụng .NET Framework 4.7 và Windows 10 Creators Update (1703) hoặc mới hơn, bạn phải thực hiện những việc sau để định cấu hình hỗ trợ DPI cao cho ứng dụng Windows Form của mình:

Tuyên bố khả năng tương thích với Windows 10.

Để thực hiện việc này, hãy thêm phần sau vào manifesttệp của bạn :

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

Bật nhận thức DPI cho mỗi màn hình trong app.configtệp.

Windows Forms giới thiệu một System.Windows.Forms.ApplicationConfigurationSection mới phần tử để hỗ trợ các tính năng và tùy chỉnh mới được thêm vào bắt đầu từ .NET Framework 4.7. Để tận dụng các tính năng mới hỗ trợ DPI cao, hãy thêm phần sau vào tệp cấu hình ứng dụng của bạn.

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

Quan trọng

Trong các phiên bản trước của .NET Framework, bạn đã sử dụng tệp kê khai để thêm hỗ trợ DPI cao. Cách tiếp cận này không còn được khuyến nghị nữa vì nó ghi đè các cài đặt được xác định trên tệp app.config.

Gọi phương thức EnableVisualStyles tĩnh.

Đây phải là lệnh gọi phương thức đầu tiên trong điểm nhập ứng dụng của bạn. Ví dụ:

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

Ưu điểm của điều này là hỗ trợ các kịch bản DPI động trong đó người dùng thay đổi DPI hoặc hệ số tỷ lệ sau khi ứng dụng Windows Forms đã được khởi chạy.

Nguồn: Hỗ trợ DPI cao trong Windows Forms


3

Không có đề xuất nào trong số này phù hợp với tôi nhưng, có điều gì đó đã xảy ra sau khi tôi xóa Form.Font = new... khỏi Form.Design.cs, biểu mẫu bắt đầu chia tỷ lệ lại đúng cách, nó hoạt động nếu Phông chữ được xác định trong hàm tạo hay không. Tại sao? Ai đó có thể giải thích, tôi chỉ có thể nói về những thay đổi mà tôi đã thực hiện và mất vài phút để tìm ra nguyên nhân gốc rễ cho biểu mẫu mà tôi đang làm. Hy vọng nó giúp.


2

Vì ít nhất Visual Studio 2017 bạn chỉ phải thêm tệp kê khai và bỏ ghi chú phần này:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
</application>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.