如何获取WPF应用当前所在显示器的DPI缩放比例?
获取WPF窗口当前所在显示器的DPI缩放比例
问题原因
VisualTreeHelper.GetDpi(Window)返回的是窗口创建时所在显示器的DPI,当窗口移动到其他显示器后,该值不会自动更新,因此你会一直得到主显示器的缩放比例。
两种可行解决方案
方案1:依赖System.Windows.Forms实现
先在项目中安装NuGet包System.Windows.Forms,然后通过Screen类定位当前窗口所在显示器,再计算DPI缩放比例:
using System.Windows; using System.Windows.Forms; using System.Windows.Media; public static class DpiHelper { public static DpiScale GetCurrentMonitorDpi(Window targetWindow) { // 获取窗口句柄对应的屏幕 var windowHandle = new System.Windows.Interop.WindowInteropHelper(targetWindow).Handle; Screen currentScreen = Screen.FromHandle(windowHandle); // 计算DPI缩放比例(默认96为100%缩放) double dpiScaleX = (96.0 * currentScreen.Bounds.Width) / currentScreen.WorkingArea.Width; double dpiScaleY = (96.0 * currentScreen.Bounds.Height) / currentScreen.WorkingArea.Height; return new DpiScale(dpiScaleX / 96, dpiScaleY / 96); } }
调用示例:
// 在窗口类中调用 var currentDpiScale = DpiHelper.GetCurrentMonitorDpi(this); double scaleFactor = currentDpiScale.DpiScaleX; // 1.0=100%,2.0=200%
方案2:调用Win32 API实现(无额外依赖)
如果不想引入System.Windows.Forms,可以直接调用Win32原生API获取当前显示器的准确DPI:
using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Media; public static class DpiHelper { [DllImport("user32.dll")] private static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); [DllImport("shcore.dll")] private static extern int GetDpiForMonitor(IntPtr hmonitor, MonitorDpiType dpiType, out uint dpiX, out uint dpiY); public enum MonitorDpiType { MDT_EFFECTIVE_DPI = 0, // 获取系统生效的DPI(对应显示设置中的缩放比例) MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2 } public static DpiScale GetCurrentMonitorDpi(Window targetWindow) { var windowHandle = new System.Windows.Interop.WindowInteropHelper(targetWindow).Handle; // 获取窗口最近的显示器句柄 IntPtr monitorHandle = MonitorFromWindow(windowHandle, 0x00000002); if (GetDpiForMonitor(monitorHandle, MonitorDpiType.MDT_EFFECTIVE_DPI, out uint dpiX, out uint dpiY) == 0) { return new DpiScale(dpiX / 96.0, dpiY / 96.0); } // 调用失败时回退到VisualTreeHelper的结果 return VisualTreeHelper.GetDpi(targetWindow); } }
补充说明
- 当窗口跨多个显示器时,上述方法会返回窗口中心或最近的显示器的DPI。
- 若需要监听窗口跨显示器移动后的DPI变化,可以订阅窗口的
LocationChanged事件,在事件触发时重新获取DPI。
内容的提问来源于stack exchange,提问作者wforl
相关产品推荐
相关产品推荐

