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

 

參考文章:

 

關鍵字:監聽分辨率、分辨率變更


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM