wpf 如何获得所有屏幕的 DPI 比例?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29438430/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:03:47  来源:igfitidea点击:

How to get DPI scale for all screens?

c#wpfwindows

提问by Sarah

I need to get the DPI scale, as set from Control Panel > Display, for each of the screens connected to the computer, even those that do not have a WPF window open. I have seen a number of ways to get DPI (for example, http://dzimchuk.net/post/Best-way-to-get-DPI-value-in-WPF) but these seem to be dependent on either Graphics.FromHwnd(IntPtr.Zero)or PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice.

我需要为连接到计算机的每个屏幕获取 DPI 比例,如从“控制面板”>“显示”设置的那样,即使是那些没有打开 WPF 窗口的屏幕。我已经看到了多种获取 DPI 的方法(例如,http://dzimchuk.net/post/Best-way-to-get-DPI-value-in-WPF),但这些似乎依赖于Graphics.FromHwnd(IntPtr.Zero)PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice

Is there a way to get the DPI settings for each individual screen?

有没有办法为每个单独的屏幕获取 DPI 设置?

Background - I am creating a layout configuration editor so that the user can set up their configuration prior to launch. For this, I draw each of the screens relative to each other. For one configuration we are using a 4K display that has a larger than default DPI scale set. It is drawing much smaller than it physically appears in relation to the other screens because it reports as the same resolution as the other screens.

背景 - 我正在创建一个布局配置编辑器,以便用户可以在启动之前设置他们的配置。为此,我绘制了每个相对于彼此的屏幕。对于一种配置,我们使用的 4K 显示器比默认 DPI 比例集大。由于它报告的分辨率与其他屏幕的分辨率相同,因此它的绘制比实际显示的要小得多。

回答by Koopakiller

I found a way to get the dpi's with the WinAPI. As first needs references to System.Drawingand System.Windows.Forms. It is possible to get the monitor handle with the WinAPI from a point on the display area - the Screenclass can give us this points. Then the GetDpiForMonitorfunction returns the dpi of the specified monitor.

我找到了一种使用 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,
}

There are three types of scaling, you can find a description in the MSDN.

缩放有三种类型,您可以在 MSDN 中找到说明

I tested it quickly with a new WPF application:

我用一个新的 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;
    }
}

I hope it helps!

我希望它有帮助!