WinForms中如何强制刷新更新Screen对象?
WinForms强制刷新Screen对象的有效方法
针对修改显示缩放或显示属性后,Screen.AllScreens返回旧数据的问题,核心原因是WinForms内部的s_screens静态缓存字段未被正确置空。以下是几种可行的强制刷新方案:
方案1:通过反射直接清空缓存字段
因为s_screens是Screen类的私有静态字段,我们可以用反射绕过访问限制,直接将其置为null,这样下次调用AllScreens时就会重新从系统读取最新的显示配置:
using System.Reflection; // 获取Screen类的私有静态字段s_screens FieldInfo? screensField = typeof(System.Windows.Forms.Screen).GetField( "s_screens", BindingFlags.NonPublic | BindingFlags.Static ); if (screensField != null) { // 置空缓存 screensField.SetValue(null, null); } // 此时再获取AllScreens就是最新数据 var updatedScreens = System.Windows.Forms.Screen.AllScreens;
方案2:手动触发系统事件的缓存清理逻辑
WinForms原本会通过SystemEvents.DisplaySettingsChanging事件触发s_screens置空,但某些场景下该事件未被正确绑定或触发。我们可以手动调用对应的处理方法:
using System.Reflection; // 获取OnDisplaySettingsChanging私有静态方法 MethodInfo? handlerMethod = typeof(System.Windows.Forms.Screen).GetMethod( "OnDisplaySettingsChanging", BindingFlags.NonPublic | BindingFlags.Static ); if (handlerMethod != null) { // 调用方法触发缓存清空 handlerMethod.Invoke(null, new object?[] { null, EventArgs.Empty }); }
方案3:组合操作确保刷新
为了避免单一方法失效,可以同时执行缓存清空和重新绑定事件:
using System.Reflection; using Microsoft.Win32; // 先清空缓存 FieldInfo? screensField = typeof(System.Windows.Forms.Screen).GetField( "s_screens", BindingFlags.NonPublic | BindingFlags.Static ); screensField?.SetValue(null, null); // 重新绑定DisplaySettingsChanging事件(确保后续变更能自动触发缓存清理) MethodInfo? handlerMethod = typeof(System.Windows.Forms.Screen).GetMethod( "OnDisplaySettingsChanging", BindingFlags.NonPublic | BindingFlags.Static ); if (handlerMethod != null) { EventHandler handler = (EventHandler)Delegate.CreateDelegate( typeof(EventHandler), handlerMethod ); SystemEvents.DisplaySettingsChanging += handler; }
补充说明
之前尝试发送WM_DISPLAYCHANGE广播消息无效的原因是:该消息本身不会直接清空WinForms的缓存,而是依赖SystemEvents.DisplaySettingsChanging事件的绑定处理。如果事件未正确注册,缓存就不会被置空。
内容的提问来源于stack exchange,提问作者Horst Walter
相关产品推荐
相关产品推荐

