首页 > 编程语言 >C# 监听窗口分辨率/DPI变更

C# 监听窗口分辨率/DPI变更

时间:2023-03-08 15:44:31浏览次数:54  
标签:IntPtr 窗口 C# 变更 var 屏幕 监听 DPI

C# 监听窗口分辨率/DPI变更

 

当程序运行,窗口已经加载后,如果修改屏幕分辨率,会影响窗口的正常显示。

举个案例:

悬浮窗口,显示在屏幕右下角。当分辨率、文本显示比例变更后,窗口位置可能会超出屏幕范围。

所以当屏幕变更时,我们需要知道准确的时机,然后针对的处理。

通过窗口消息监听屏幕显示变更

对窗口添加钩子

1     var windowInteropHelper = new WindowInteropHelper(this);
2     var hwnd = windowInteropHelper.Handle;
3     HwndSource source = HwndSource.FromHwnd(hwnd);
4     source?.AddHook(Hook);

对窗口消息添加处理

复制代码
1     private const int WmDisplayChange = 0x007e;
2     private IntPtr Hook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
3     {
4         if (msg == WmDisplayChange)
5         {
6             SetLocation();
7         }
8         return IntPtr.Zero;
9     }
复制代码

“0x007e”是屏幕分辨率以及文本显示比例变更对应的消息标识。

“0x02E0”是文本显示比例变更的消息标识。这个标识更具体,但需要在程序未开启DPI感知后,才会收到0x02E0消息。

通过系统事件监听屏幕显示变更

上面通过钩子来判断相应的窗口消息,其实也有系统事件封装了这类的处理:

复制代码
1     public MainWindow()
2     {
3         InitializeComponent();
4         Microsoft.Win32.SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
5     }
6     private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
7     {
8 
9     }
复制代码

屏幕变更时,回调事件参数如下:

这个系统静态事件和窗口消息是一样的,触发次数和时机一样。调试发现触发顺序:窗口消息->系统静态事件。

因为这个事件没有任何实际的数据,所以只能通过其它方式获取DPI。

更新窗口位置

屏幕显示变更的时机有了,可以根据时间添加相应的操作:

复制代码
 1     private void SetLocation()
 2     {
 3         var dpiForWindow = GetDpiForWindow(new WindowInteropHelper(this).Handle);
 4         var windowRatio = (double)dpiForWindow / 96.0;
 5 
 6         var intPtr = new WindowInteropHelper(this).Handle;//获取当前窗口的句柄
 7         var screen = Screen.FromHandle(intPtr);//获取当前屏幕
 8         var locationX = (screen.Bounds.Width - 300) / windowRatio;
 9         var locationY = (screen.Bounds.Height - 300) / windowRatio;
10         Left = locationX;
11         Top = locationY;
12     }
复制代码

获取对应屏幕的DPI信息,并转换成WPF的DPI比例,计算出窗口的最新位置。

 其它的获取方式,可以见:C# 获取当前屏幕DPI - 唐宋元明清2188 - 博客园 (cnblogs.com)

程序开启DPI感知

如果你通过上面代码,获取的DPI依旧是1,那应该是没有开启DPI感知,请按如下添加就行了:

true/pm,意思是开启屏幕DPI感知。具体的dpiAware参数介绍,可以了解下毅仔的博客:支持 Windows 10 最新 PerMonitorV2 特性的 WPF 多屏高 DPI 应用开发 - walterlv

标签:IntPtr,窗口,C#,变更,var,屏幕,监听,DPI
From: https://www.cnblogs.com/liuyuchuan/p/17192194.html

相关文章