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

举个案例:

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

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

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

对窗口添加钩子

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

参考文章:

关键字:监听分辨率、分辨率变更

C# 监听窗口分辨率/DPI变更的更多相关文章

  1. vue项目如何监听窗口变化,达到页面自适应?

    [自适应]向来是前端工程师需要解决的一大问题--即便作为当今非常火热的vue框架,也无法摆脱--虽然elementui.iview等开源UI组件库层出不穷,但官方库毕竟不可能满足全部需求,因此我们可以 ...

  2. Java面板Panel的使用,监听窗口关闭事件

    面板Panel的使用 待解决问题: 1.设计模式:适配器模式 2.frame.setLayout(null); package GUI; import javax.swing.*; import ja ...

  3. vue 中监听窗口发生变化,触发监听事件, window.onresize && window.addEventListener('resize',fn) ,window.onresize无效的处理方式

    // 开始这样写,不执行 window.onresize = function() { console.log('窗口发生变化') } // 改成window监听事件 window.addEventL ...

  4. React监听窗口变化事件

    功能说明:本例子采用MUI table组件 + React实现. 需求描述:固定表头,列表高度随浏览器窗口的改变而改变.(本例中当窗口高度小于472像素后,便不作限制) 实现简介:1.监听浏览器窗口, ...

  5. 第35天学习打卡(输入框 TextField监听 简易计算器,组合+内部类回顾复习 画笔 鼠标监听 窗口监听 键盘监听)

    1.输入框 TextField监听  package com.kuang.lesson02; ​ import java.awt.*; import java.awt.event.ActionEven ...

  6. js判断是否安装某个android app,没有安装下载该应用(websocket通信,监听窗口失去焦点事件)

    现在经常有写场景需要提示用户下载app, 但是如果用户已经安装,我们希望是直接打开app. 实际上,js是没有判断app是否已经安装的方法的,我们只能曲线救国. 首先,我们需要有call起app的sc ...

  7. Python窗口学习之监听窗口变化触发函数

    在窗口大小发生变化后,往往组件也需要调整 代码: #空间适应屏幕 def window_resiz(self,event=None): print(window.winfo_height()) pri ...

  8. openlayers 3监听地图分辨率变化事件

    map.getView().on('change:resolution',checkZoom);//checkZoom为调用的函数 function checkZoom() { // alert(&q ...

  9. js 监听窗口变化

    window.onresize = function () {.....}jquery $(window).resize(function)

随机推荐

  1. Ubuntu系统Root用户无法登录解决办法

    默认 系统 root 登录 图形界面,出现 登录失败.解决方法如下: 1,登录普通用户, 打开终端执行命令, 使用su root或sudo -i切换到root用户(必须) su root 按照提示输入 ...

  2. 持续集成环境(4)-Jenkins凭证管理

    凭据可以用来存储需要密文保护的数据库密码.Gitlab密码信息.Docker私有仓库密码等,以便 Jenkins可以和这些第三方的应用进行交互. 安装Credentials Binding插件 要在J ...

  3. ELK集群基础环境初始化

    集群基础环境初始化 1.准备虚拟机 192.168.1.7 192.168.1.6192.168.1.183 2.切换为国内centos源 3.修改sshd服务优化 [root@elk01 ~]# s ...

  4. java中的4种引用和GC Roots

    https://juejin.im/post/5d06de9d51882559ee6f4212?utm_source=gold_browser_extension 1.首先,四种引用如下: Final ...

  5. loadrunner入门(关联)

    左右边界:提取第一个id web_reg_save_param_ex(                 "ParamName=Id",         "LB=//OK[ ...

  6. avx

    编译选项: CXXFLAGS += -mavx2 #include <immintrin.h> #include <cmath> void reset_xy(int *x, i ...

  7. 使用Wireshark查看HTTPS中TLS握手过程

    通过使用Wireshark抓包分析TLS握手的过程,可以更容易理解和验证TLS协议,本文将先介绍Wireshark解密HTTPS流量的方法,然后分别验证TLS握手过程和TLS会话恢复的过程. 一.使用 ...

  8. OS基础-四大基本特征

    现代计算机操作系统的四大基本特性(并发/共享/虚拟/异步) 1.并发性 1.1.并发与并行区别 并发是指宏观上在一段时间内能同时运行多个程序,而并行则指同一时刻能运行多个指令.并发需要硬件支持,如多流 ...

  9. modbus通讯协议详解

    1.Modbus 协议简介  Modbus协议是一种已广泛应用于当今工业控制领域的通用通讯协议.通过此协议,控制器相互之间.或控制器经由网络(如以太网)可以和其它设备之间进行通信.Modbus协议使用 ...

  10. 《MySQL是怎样运行的》第三章小结