天天看點

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”是螢幕分辨率以及文本顯示比例變更對應的消息辨別。

通過系統事件監聽螢幕顯示變更

上面通過鈎子來判斷相應的視窗消息,其實也有系統事件封裝了這類的處理:

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     }      

螢幕變更時,回調事件參數如下:

C# 監聽視窗分辨率/DPI變更

這個系統靜态事件和視窗消息是一樣的,觸發次數和時機一樣。調試發現觸發順序:視窗消息->系統靜态事件。

更新視窗位置

螢幕顯示變更的時機有了,可以根據時間添加相應的操作:

1     private void SetLocation()
 2     {
 3         using (Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(this).Handle))
 4         {
 5             double dpixRatioX = currentGraphics.DpiX / 96;
 6             double dpixRatioY = currentGraphics.DpiY / 96;
 7 
 8             var intPtr = new WindowInteropHelper(this).Handle;//擷取目前視窗的句柄
 9             var screen = Screen.FromHandle(intPtr);//擷取目前螢幕
10             var locationX = (screen.Bounds.Width - 300) / dpixRatioX;
11             var locationY = (screen.Bounds.Height - 300) / dpixRatioY;
12             Left = locationX;
13             Top = locationY;
14         }
15     }      

擷取對應螢幕的DPI資訊,并轉換成WPF的DPI比例,計算出視窗的最新位置。

C# 監聽視窗分辨率/DPI變更

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

作者:唐宋元明清2188

出處:http://www.cnblogs.com/kybs0/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須在文章頁面給出原文連接配接,否則保留追究法律責任的權利。