Screen.PrimaryScreen.Bounds.Width和Height是获取主显示器逻辑分辨率最直接方式,已适配系统DPI缩放,但返回的是含任务栏的显示区域,非物理分辨率。

用 Screen.PrimaryScreen.Bounds 获取主显示器分辨率最直接
多数情况下,你真正需要的是主屏幕的宽高,而不是“所有显示器拼起来”的尺寸。Screen.PrimaryScreen.Bounds 返回一个 Rectangle,它的 Width 和 Height 就是主显示器的像素宽度和高度(不含任务栏等系统边框)。
常见错误是误用 Screen.PrimaryScreen.WorkingArea——它会扣除任务栏、停靠窗口等占用区域,得到的是“可用工作区”,不是物理分辨率。
- 如果程序只运行在主屏,直接读
Bounds.Width和Bounds.Height - 注意:这个值受 Windows 缩放设置影响。比如 1920×1080 屏幕设为 125% 缩放时,
Bounds仍返回1920×1080,但实际逻辑像素可能被缩放处理 - WPF 或 WinForms 都能用,无需额外引用,属于
System.Windows.Forms命名空间
多显示器环境下用 Screen.AllScreens 枚举每个屏幕
当你的应用要适配扩展显示(比如双屏、投屏),必须遍历 Screen.AllScreens 数组,不能只看主屏。
每个 Screen 对象都带 Bounds、WorkingArea、DeviceName(如 \.DISPLAY1)等字段,可用来识别物理设备或定位窗口。
-
Screen.AllScreens返回顺序不固定,不要依赖索引取第二块屏;应结合IsPrimary或Bounds.Location判断位置关系 - 某些远程桌面或虚拟显卡场景下,
AllScreens可能返回空数组或仅含一个“虚拟屏”,需加空检查 - 若需获取 DPI 缩放比例,得配合
Graphics.FromHwnd(IntPtr.Zero).DpiX等方式,Screen类本身不暴露 DPI
WinForms 中 Form 的 Screen 属性比硬编码更可靠
如果你在窗体里调整布局,别直接用 Screen.PrimaryScreen,而该用 this.Screen——它返回当前窗体所在屏幕的 Screen 实例,对跨屏拖动、多 DPI 混合环境更鲁棒。
例如用户把窗口拖到副屏,this.Screen.Bounds 自动切换为副屏分辨率,而 Screen.PrimaryScreen 还是主屏数据。
- 仅限 WinForms;WPF 请用
SystemParameters.PrimaryScreenWidth或VisualTreeHelper.GetRootVisual(this)配合TransformToDevice -
this.Screen在窗体构造函数中可能为 null(尚未关联屏幕),建议在Load或Shown事件里访问 - 如果窗体跨多个显示器(比如拉得很宽),
this.Screen返回的是其左上角所在的屏幕,不是覆盖区域的并集
高 DPI 场景下 Bounds 和实际像素不一致怎么办
Windows 设置了缩放(如 125%、150%)后,Screen.Bounds 仍返回原始设备像素值,但 GDI/WPF 渲染会按逻辑单位缩放——这导致“获取到的分辨率”和“绘图时的坐标系”错位。
这不是 bug,而是 Windows 的 DPI 感知模型决定的。.NET 5+ 默认启用 Per-Monitor DPI 感知,但旧项目可能仍是 System DPI 感知模式。
- 检查应用 manifest 是否启用了
dpiAwareness="PerMonitorV2",否则Screen类返回的数据在高 DPI 下不可靠 - 想获取真实物理像素?用
Graphics.DpiX/Y计算:physicalWidth = Bounds.Width * DpiX / 96(96 是默认 DPI) - WinForms 中可重写
OnHandleCreated并调用SetProcessDpiAwarenessContextAPI 强制启用,但需管理员权限或清单声明
真正麻烦的不是怎么取宽高,而是取完之后是否意识到它只是“当前 DPI 感知级别下的逻辑值”。同一台机器,不同启动方式(快捷方式 vs 命令行)、不同兼容性设置,都可能让 Screen 返回看似矛盾的结果。


















