2015-04-03 50 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