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
参考文章:
- Windows 下的高 DPI 应用开发(UWP / WPF / Windows Forms / Win32) - walterlv
- Windows DPI Awareness for WPF - walterlv
关键字:监听分辨率、分辨率变更
C# 监听窗口分辨率/DPI变更的更多相关文章
- vue项目如何监听窗口变化,达到页面自适应?
[自适应]向来是前端工程师需要解决的一大问题--即便作为当今非常火热的vue框架,也无法摆脱--虽然elementui.iview等开源UI组件库层出不穷,但官方库毕竟不可能满足全部需求,因此我们可以 ...
- Java面板Panel的使用,监听窗口关闭事件
面板Panel的使用 待解决问题: 1.设计模式:适配器模式 2.frame.setLayout(null); package GUI; import javax.swing.*; import ja ...
- vue 中监听窗口发生变化,触发监听事件, window.onresize && window.addEventListener('resize',fn) ,window.onresize无效的处理方式
// 开始这样写,不执行 window.onresize = function() { console.log('窗口发生变化') } // 改成window监听事件 window.addEventL ...
- React监听窗口变化事件
功能说明:本例子采用MUI table组件 + React实现. 需求描述:固定表头,列表高度随浏览器窗口的改变而改变.(本例中当窗口高度小于472像素后,便不作限制) 实现简介:1.监听浏览器窗口, ...
- 第35天学习打卡(输入框 TextField监听 简易计算器,组合+内部类回顾复习 画笔 鼠标监听 窗口监听 键盘监听)
1.输入框 TextField监听 package com.kuang.lesson02; import java.awt.*; import java.awt.event.ActionEven ...
- js判断是否安装某个android app,没有安装下载该应用(websocket通信,监听窗口失去焦点事件)
现在经常有写场景需要提示用户下载app, 但是如果用户已经安装,我们希望是直接打开app. 实际上,js是没有判断app是否已经安装的方法的,我们只能曲线救国. 首先,我们需要有call起app的sc ...
- Python窗口学习之监听窗口变化触发函数
在窗口大小发生变化后,往往组件也需要调整 代码: #空间适应屏幕 def window_resiz(self,event=None): print(window.winfo_height()) pri ...
- openlayers 3监听地图分辨率变化事件
map.getView().on('change:resolution',checkZoom);//checkZoom为调用的函数 function checkZoom() { // alert(&q ...
- js 监听窗口变化
window.onresize = function () {.....}jquery $(window).resize(function)
随机推荐
- 2020.11.24 javaScript匿名函数的使用
参考链接:http://www.voidcn.com/article/p-ngxxuegm-bmv.html 匿名函数: 函数表达式中创建的函数叫做匿名函数,也就是没有函数名的函数. 自执行函数: 创 ...
- python打包成exe过程中遇到的问题
先描述下初始状况: python版本为3.7.3,直接在cmd中运行pip安装pyinstaller失败,应该是最开始安装python时没有把目录添加到环境变量中(我很懒).直接在python的安装目 ...
- 漫谈Python魔术方法,见过的没见过的都在这里了
漫谈Python魔术方法,见过的没见过的都在这里了 就说一下,不深入 假的一览 提到魔术方法,学过python都应该知道一些.至少你得会__init__吧. 在我之前写的博文中有很多都涉及魔术方法.比 ...
- 使用VSCode调试C#时,Console.ReadLine()弹出命令框调试
原文链接:https://blog.csdn.net/qq_29503199/article/details/88351498 要在调试时读取输入,可以在 launch.json 中使用配置中的 ...
- PHP 数据库操作
连接数据库 连接数据库常用的函数 mysqli_connect(主机IP,用户名,密码,数据库名,端口号) // 端口号如果是3306可以省略 mysqli_connect_error():获取连接数 ...
- Python学习笔记--列表来啦!
列表的定义格式 示例: 列表的下标索引(千万别超出范围!!!) 示例: 正向和反向 取出嵌套列表的元素:(二维数组) 列表的常用的操作方法 查找某元素的下标 示例: 修改元素 插入元素 示例: 追加元 ...
- (新手向)在Linux中使用VScode编写 "Hello,world"程序,并编写测试-Ubuntu20.4
本文意在帮助 Go 语言初学者在 Linux环境下编写自己的第一个Golang程序 难点主要在 VScode 中 Go 插件的下载 与 go.mod 以及编译运行和 第一个Go测试程序的使用 前提准备 ...
- MasaFramework入门第二篇,安装MasaFramework了解各个模板
安装MasaFramework模板 执行以下命令安装最新Masa的模板 dotnet new --install Masa.Template 安装完成将出现四个模板 Masa Blazor App: ...
- 自己动手从零写桌面操作系统GrapeOS系列教程——17.用汇编语言清空屏幕
学习操作系统原理最好的方法是自己写一个简单的操作系统. 在QEMU中会默认输出一些字符,有时候会干扰我们自己输出的字符.一个比较好的办法是向将屏幕清空,再输出我们想要输出的字符.下面就来学习如何清空屏 ...
- day06-静态资源访问&Rest风格
SpringBoot之静态资源访问&REST风格请求 1.SpringBoot静态资源访问 1.1基本介绍 只要静态资源是放在类路径下的:/static./public./resources. ...