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)
随机推荐
- 过滤器函数 filtes 的使用总结
// import parseTime, formatTime and set to filter /** * Show plural label if time is plural number * ...
- C语言声明与定义的区别
转自:https://blog.csdn.net/gatieme/article/details/50640424 C++程序通常由许多文件组成,为了让多个文件访问相同的变量,C++区分了声明和定义. ...
- java获取类内容
java获取类内容 Book类 public class Book implements Serializable { private int id; private String name; pri ...
- idea导入数据库
yml文件(在启动项文件(main)里,eg:springbook文件里面) sh-bean里org.example.sh.beans的Category类 CategoryDAO名字要和Categ ...
- 了解RTT 和RTO 对于TCP 重传的影响
前言 我们已经在很多地方了解TCP 的功能和常用字段.但是TCP 传输发生的异常情况总是让我们很棘手,不知改如何处理.陷入迷茫之中.本文章只针对RTT 和RTO 做了解. 描述 RTT (Round ...
- 谷歌翻译不能用解决办法(谷歌翻译关闭后,如何继续使用Chrome浏览器的翻译功能?)
1.查找 IP 虽然谷歌不再提供 translate.google.cn 网页版的服务了,但谷歌翻译的 API 服务还在. 只需要通过 hosts 重定向至国内服务器,即可恢复使用. 1.Ping ...
- jmeter--操作
Jmeter响应断言--正则表达式判断纯数字 这样是匹配14位数字,如果响应是纯数字可以直接用上 jmeter 随机取一个值的方法 1.添加用户自定义变量 在要用到随机值的地方写入 ${__Ran ...
- Spring设计模式——原型模式
原型模式 原型模式(Prototype Pattern),是指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象. 原型模式主要适用于以下场景: 类初始化消耗资源较多 使用new生成一个对象 ...
- Nacos 实现 AP+CP原理[Raft 算法 NO]
来源于网络 一.什么是 Raft算法 Raft 适用于一个管理日志一致性的协议,相比于 Paxos 协议 Raft 更易于理解和去实现它.为了提高理解性,Raft 将一致性算法分为了几个部分,包括领导 ...
- [C++STL教程]7.priority_queue优先队列入门学习!零基础都能听懂的教程
不知不觉C++STL教程系列已经第7期了.之前我们介绍过:vector, queue, stack, set, map等等数据结构. 今天我们来学习一个新的stl容器:priority_queue优先 ...