2015-04-03 15 views
8

Potrzebuję uzyskać skalę DPI, zgodnie z ustawieniem z Panelu sterowania> Wyświetlanie, dla każdego ekranu podłączonego do komputera, nawet tych, które nie mają otwartego okna WPF. Widziałem wiele sposobów na uzyskanie DPI (na przykład http://dzimchuk.net/post/Best-way-to-get-DPI-value-in-WPF), ale wydaje się, że są one zależne od Graphics.FromHwnd(IntPtr.Zero) lub PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice.Jak uzyskać skalę DPI dla wszystkich ekranów?

Czy istnieje sposób na uzyskanie ustawień DPI dla każdego pojedynczego ekranu?

Tło - Tworzę edytor konfiguracji układu, aby użytkownik mógł skonfigurować swoją konfigurację przed uruchomieniem. W tym celu rysuję każdy z ekranów względem siebie. Dla jednej konfiguracji używamy wyświetlacza 4K, który ma większy niż domyślny zestaw skali DPI. Rysunek jest znacznie mniejszy niż fizycznie pojawia się w stosunku do innych ekranów, ponieważ jest raportowany jako ta sama rozdzielczość co pozostałe ekrany.

+0

Czy możesz po prostu utworzyć fałszywe okno na każdym ekranie i pobrać informacje w ten sposób? –

+0

Możesz przejść do poprzedniego komentarza, w przeciwnym razie będziesz musiał wyliczyć urządzenia wyświetlające i uzyskać DPI w ten sposób. – Kcvin

+0

System Windows obsługuje teraz DPI dla poszczególnych ekranów, począwszy od wersji 8.1. Najprawdopodobniej natkniesz się na to w konfiguracji, w której masz jeden kosztowny wyświetlacz "siatkówkowy" i inny prosty, zwykle projektor. Wersja dla WPF [jest tutaj] (https://msdn.microsoft.com/en-us/library/windows/desktop/ee308410%28v=vs.85%29.aspx). –

Odpowiedz

11

Znalazłem sposób na uzyskanie rozdzielczości za pomocą interfejsu WinAPI. Jako pierwsza potrzebuje referencji do System.Drawing i System.Windows.Forms. Możliwe jest uzyskanie uchwytu monitora za pomocą interfejsu WinAPI z punktu na obszarze wyświetlania - klasa Screen może dać nam te punkty. Następnie funkcja GetDpiForMonitor zwraca wartość dpi określonego monitora.

public static class ScreenExtensions 
{ 
    public static void GetDpi(this System.Windows.Forms.Screen screen, DpiType dpiType, out uint dpiX, out uint dpiY) 
    { 
     var pnt = new System.Drawing.Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1); 
     var mon = MonitorFromPoint(pnt, 2/*MONITOR_DEFAULTTONEAREST*/); 
     GetDpiForMonitor(mon, dpiType, out dpiX, out dpiY); 
    } 

    //https://msdn.microsoft.com/en-us/library/windows/desktop/dd145062(v=vs.85).aspx 
    [DllImport("User32.dll")] 
    private static extern IntPtr MonitorFromPoint([In]System.Drawing.Point pt, [In]uint dwFlags); 

    //https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx 
    [DllImport("Shcore.dll")] 
    private static extern IntPtr GetDpiForMonitor([In]IntPtr hmonitor, [In]DpiType dpiType, [Out]out uint dpiX, [Out]out uint dpiY); 
} 

//https://msdn.microsoft.com/en-us/library/windows/desktop/dn280511(v=vs.85).aspx 
public enum DpiType 
{ 
    Effective = 0, 
    Angular = 1, 
    Raw = 2, 
} 

Istnieją trzy rodzaje skalowania, można znaleźć description in the MSDN.

Testowałem go szybko z nowej aplikacji WPF:

private void Window_Loaded(object sender, System.Windows.RoutedEventArgs e) 
{ 
    var sb = new StringBuilder(); 
    sb.Append("Angular\n"); 
    sb.Append(string.Join("\n", Display(DpiType.Angular))); 
    sb.Append("\nEffective\n"); 
    sb.Append(string.Join("\n", Display(DpiType.Effective))); 
    sb.Append("\nRaw\n"); 
    sb.Append(string.Join("\n", Display(DpiType.Raw))); 

    this.Content = new TextBox() { Text = sb.ToString() }; 
} 

private IEnumerable<string> Display(DpiType type) 
{ 
    foreach (var screen in System.Windows.Forms.Screen.AllScreens) 
    { 
     uint x, y; 
     screen.GetDpi(type, out x, out y); 
     yield return screen.DeviceName + " - dpiX=" + x + ", dpiY=" + y; 
    } 
} 

Mam nadzieję, że to pomaga!

+0

Musiałem zmienić 'MonitorFromPoint (Point, short)' na 'MonitorFromPoint (Point, uint)', ale poza tym działa świetnie. Dziękuję Ci! – Sarah

+0

@ Sarah masz rację, zmieniłem deklarację. – Koopakiller

+0

Krótka notatka, działa tylko w systemie Windows 8 i nowszych wersjach. –

Powiązane problemy