双显示器不同缩放比例下切换窗口如何获取正确DPI?
解决多显示器DPI获取不准确的问题
看起来你在多显示器不同缩放比例的场景下,遇到了DPI获取始终为固定值的问题,我来帮你一步步排查和解决:
1. 先修正代码里的参数传递错误
你的GetDpi扩展方法签名是:
public static void GetDpi(this System.Windows.Forms.Screen screen, DpiType dpiType, out uint dpiX, out uint dpiY)
但调用时错误地多传了currentMonitor.MonitorHandle参数——扩展方法的第一个screen参数是通过this关键字隐式传递的,你只需要传入DpiType和输出参数即可。
修正后的调用代码:
uint x = 0, y = 0; foreach (var screen in System.Windows.Forms.Screen.AllScreens) { if (screen.DeviceName == currentMonitor.Name) { // 移除多余的currentMonitor.MonitorHandle参数 screen.GetDpi(DpiType.Effective, out x, out y); break; } }
2. 选择正确的DpiType枚举值
你用的DpiType.Angular是用来获取角度DPI(每英寸的像素角度),这不是我们需要的显示器缩放对应DPI。应该选以下两种:
DpiType.Effective:获取系统缩放后的有效DPI(比如150%缩放对应144,100%对应96)DpiType.Raw:获取显示器的物理原生DPI
确保你的DpiType枚举定义正确:
public enum DpiType { Effective = 0, Angular = 1, Raw = 2 }
3. 必须开启应用程序的Per-Monitor DPI感知
这是最关键的一步,如果你的应用没开启对应感知模式,系统会自动对窗口进行缩放,导致你获取的DPI始终是默认值。
在项目中添加或修改app.manifest文件,加入以下配置:
<application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <!-- 开启Per-Monitor V2 DPI感知,支持Win10 1607及以上版本 --> <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">PerMonitorV2</dpiAware> <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness> </windowsSettings> </application>
如果没有app.manifest,右键项目 → 添加 → 新建项 → 选择「应用程序清单文件」即可。
4. 监听窗口切换显示器时的DPI变化事件
当窗口在不同显示器间切换时,WinForms(.NET Framework 4.7+/.NET Core 3.0+)提供了DpiChanged事件,你可以通过这个事件及时获取新的DPI:
private void YourForm_DpiChanged(object sender, DpiChangedEventArgs e) { uint currentDpiX, currentDpiY; // 获取当前窗口所在屏幕的DPI Screen.FromHandle(this.Handle).GetDpi(DpiType.Effective, out currentDpiX, out currentDpiY); // 在这里更新UI元素或存储最新的DPI值 }
关于你的扩展方法
你的GetDpi扩展方法本身逻辑是没问题的:通过屏幕边界内的点获取对应显示器句柄,再调用GetDpiForMonitor获取DPI,只要完成上述几个修正点,就能正确获取不同显示器的DPI了。
内容的提问来源于stack exchange,提问作者Cs.Sz
相关产品推荐
相关产品推荐

