2015-04-03 57 views
8

對於連接到計算機的每個屏幕,即使那些沒有打開WPF窗口的屏幕,我也需要從控制面板>顯示設置中獲取DPI比例。我已經看到了許多獲得DPI的方法(例如,http://dzimchuk.net/post/Best-way-to-get-DPI-value-in-WPF),但這些方法似乎取決於Graphics.FromHwnd(IntPtr.Zero)PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice如何獲得所有屏幕的DPI比例?

有沒有辦法讓每個屏幕的DPI設置?

背景 - 我正在創建佈局配置編輯器,以便用戶可以在啓動之前設置其配置。爲此,我繪製每個屏幕相對於彼此。對於一種配置,我們使用的是具有大於默認DPI比例集的4K顯示器。它比其他屏幕實際顯示的尺寸小得多,因爲它報告的分辨率與其他屏幕相同。

+0

你能在每個屏幕上創建一個虛擬窗口並以這種方式獲取信息嗎? – 2015-04-03 19:40:02

+0

你可以與以前的評論,否則你將不得不枚舉顯示設備,並獲得DPI的方式。 – Kcvin 2015-04-03 21:48:51

+0

Windows現在支持從8.1開始的每個屏幕DPI。您可能會遇到這種情況,您需要安裝一個昂貴的「視網膜」顯示屏和另一個普通投影儀,通常是投影儀。 WPF背景資料[在這裏](https://msdn.microsoft.com/en-us/library/windows/desktop/ee308410%28v=vs.85%29.aspx)。 – 2015-04-06 19:09:47

回答

11

我找到了一種方法來獲得與WinAPI的dpi的。首先需要參考System.DrawingSystem.Windows.Forms。可以從顯示區域上的一點獲得帶有WinAPI的顯示器手柄 - Screen課程可以給我們這點。然後GetDpiForMonitor函數返回指定監視器的dpi。

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, 
} 

有三種類型的結垢,你可以找到一個description in the MSDN

我有一個新的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; 
    } 
} 

我希望它能幫助!

+0

我不得不將'MonitorFromPoint(Point,short)'改成'MonitorFromPoint(Point,uint)',但除此之外它效果很好。謝謝! – Sarah 2015-04-06 15:05:25

+0

@Sarah你是對的,我改變了聲明。 – Koopakiller 2015-04-06 18:42:26

+0

快速注意,這隻適用於Windows 8及更高版本。 – 2017-03-31 15:35:20