Screen.AllScreens 可获取所有显示器的 Bounds(含位置和宽高)及 WorkingArea,需配合 per-monitor V2 manifest 实现准确 DPI 感知,否则 Bounds 返回逻辑像素而非物理分辨率。
怎么用 Screen.AllScreens 拿到所有显示器的尺寸
直接遍历 screen.allscreens 数组,每个元素都带 bounds(含位置和宽高)和 workingarea(排除任务栏后的可用区域)。别只看主屏——screen.primaryscreen 只返回一个,多屏场景下会漏掉其他显示器。
常见错误是调用 Screen.FromControl(this) 或 Screen.FromPoint(Cursor.Position) 后只取单个结果,误以为覆盖了全部屏幕。其实它们只是“就近查找”,不是枚举。
-
Bounds.Width和Bounds.Height是物理像素尺寸,受系统缩放影响(比如 125% 缩放时,1920×1080 屏幕可能返回 2400×1350) - 如果要适配 DPI,得配合
Graphics.DpiX/DpiY或 WinForms 的AutoScaleMode使用,不能光靠像素值做布局 - 虚拟显示器(如某些远程桌面、显卡驱动模拟的屏)也会出现在
AllScreens里,需结合IsPrimary或设备名判断是否真实可用
为什么 Screen.Bounds 和实际分辨率对不上
因为 Windows 默认启用 DPI 缩放,.NET Framework 4.7+ 的 WinForms 应用默认是“每显示器 DPI 感知”(per-monitor DPI aware),但旧项目或未声明 manifest 的程序会被系统用“DPI 虚拟化”处理——此时 Bounds 返回的是逻辑像素,不是真实物理像素。
典型现象:在 4K 屏 + 150% 缩放下,Bounds 显示为 2560×1440,而真实分辨率是 3840×2160。这不是 bug,是系统故意做的兼容层。
- 查真实物理分辨率:用
Graphics.CopyFromScreen()+Bitmap截图再读Width/Height,或调用 Win32GetDeviceCaps(HORZRES/VERTRES) - 让应用真正高 DPI 感知:必须在 app.manifest 里加
,否则PerMonitorV2 Screen类行为不可靠 - .NET Core/.NET 5+ 默认更严格,没 manifest 就直接按 100% 处理,容易在高缩放设备上显示过小
WinForms 窗口跨屏拖动时怎么保持尺寸不变
直接设置 Form.Size 不行——窗口跨屏瞬间,系统可能触发自动缩放调整,尤其从 100% 屏拖到 150% 屏时,Size 值会被重算。关键在控制 Form.AutoScaleMode 和缩放时机。
- 设
this.AutoScaleMode = AutoScaleMode.None,彻底关闭自动缩放(前提是 UI 元素本身已用锚点/停靠/布局容器适配) - 在
LocationChanged事件里检查Screen.FromControl(this)是否变化,若变了就手动重设Size(用原始像素值,非设计时拖出来的 Size) - 避免在
Load事件里读Screen.PrimaryScreen.Bounds做初始化——用户可能把窗体拖到副屏再启动,此时PrimaryScreen和实际所在屏不一致
WPF 和 WinForms 获取多屏信息的区别在哪
WinForms 用 Screen.AllScreens,WPF 用 SystemParameters.VirtualScreen* 或第三方库(如 System.Windows.Forms.Screen 仍可桥接使用)。WPF 原生 API 更弱,SystemParameters.WorkArea 只返回主屏工作区,没有多屏枚举能力。
硬要纯 WPF 方案,得 P/Invoke EnumDisplayMonitors,比 WinForms 多写十几行且易出错。所以多数人直接引用 System.Windows.Forms 程序集,调 Screen.AllScreens ——它在 WPF 进程里完全可用,只要不创建 WinForms 控件。
- WPF 的
VisualTreeHelper.GetDpi(this)返回当前窗口 DPI,但无法知道其他屏的 DPI,得自己匹配Screen数组里的DeviceName和 Win32GetDpiForMonitor - WinForms 的
Screen类在 .NET 6+ 中仍是首选,文档虽老但行为稳定;WPF 官方至今没补全多屏 DPI 感知的托管封装 - 混用时注意线程:
Screen.AllScreens必须在 UI 线程调用,WPF 后台线程直接访问会抛InvalidOperationException
多屏 DPI 感知不是打开开关就完事,manifest、运行时缩放策略、UI 布局方式得全链路对齐。最容易被忽略的是:没声明 per-monitor V2 manifest 的老项目,在高分屏上连 Screen.Bounds 都不准,后面所有适配都是在错误基础上打补丁。











