我需要获得DPI比例,如控制面板中设置的>显示连接到计算机的每个屏幕,甚至是那些没有打开WPF窗口的屏幕。我已经看到了许多获取DPI的方法(例如http://dzimchuk.net/post/Best-way-to-get-DPI-value-in-WPF),但这些方法似乎取决于Graphics.FromHwnd(IntPtr.Zero)
或PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice
。
有没有办法为每个屏幕设置DPI?
背景 - 我正在创建一个布局配置编辑器,以便用户可以在启动之前设置其配置。为此,我将每个屏幕相对于彼此绘制。对于一种配置,我们使用的4K显示器具有大于默认DPI标度集。与其他屏幕相比,它绘制的图形要小得多,因为它报告的分辨率与其他屏幕相同。
答案 0 :(得分:16)
我找到了一种通过WinAPI获取dpi的方法。
首先需要引用System.Drawing
和System.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;
}
}
我希望它有所帮助!