From 74b9de2d1a470bdf4c3d736f61d4f0a47e715d40 Mon Sep 17 00:00:00 2001 From: Morten Nielsen Date: Sun, 17 Apr 2022 07:59:17 -0700 Subject: [PATCH] Correctly handle DPI change and size in device independent units --- src/WinUIEx/WindowEx.cs | 29 +++++++++++++++++++++++++---- src/WinUIEx/WindowExtensions.cs | 17 +++++++++++------ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/WinUIEx/WindowEx.cs b/src/WinUIEx/WindowEx.cs index 9ea5ffe..b2c24b2 100644 --- a/src/WinUIEx/WindowEx.cs +++ b/src/WinUIEx/WindowEx.cs @@ -26,6 +26,7 @@ public class WindowEx : Window private readonly ContentControl windowArea; private readonly WindowMessageMonitor mon; private readonly Microsoft.UI.Windowing.OverlappedPresenter overlappedPresenter; + private uint currentDpi; /// /// Initializes a new instance of the class. @@ -34,6 +35,7 @@ public WindowEx() { overlappedPresenter = Microsoft.UI.Windowing.OverlappedPresenter.Create(); AppWindow.SetPresenter(overlappedPresenter); + currentDpi = this.GetDpiForWindow(); var rootContent = new Grid(); rootContent.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto), MinHeight = 0 }); @@ -79,9 +81,28 @@ private unsafe void OnWindowMessage(object? sender, Messaging.WindowMessageEvent rect2->ptMinTrackSize.y = Math.Max((int)MinHeight, 39); } break; + case WindowsMessages.WM_DPICHANGED: + { + var newDpi = this.GetDpiForWindow(); + if (newDpi != currentDpi) + { + var oldDpi = currentDpi; + currentDpi = newDpi; + OnDpiChanged(oldDpi, newDpi); + } + break; + } } } + private void OnDpiChanged(uint oldDpi, uint newDpi) + { + var oldScale = oldDpi / 96f; + var currentSize = AppWindow.Size; + this.SetWindowSize((int)(currentSize.Width / oldScale), (int)(currentSize.Height / oldScale)); + currentDpi = newDpi; + } + private struct MINMAXINFO { #pragma warning disable CS0649 @@ -387,10 +408,10 @@ public Microsoft.UI.Windowing.AppWindowPresenterKind PresenterKind /// public double Width { - get { return AppWindow.Size.Width; } + get { return AppWindow.Size.Width / (currentDpi / 96d); } set { - this.SetWindowSize(value, AppWindow.Size.Height); + this.SetWindowSize(value, Height); } } @@ -399,10 +420,10 @@ public double Width /// public double Height { - get { return AppWindow.Size.Height; } + get { return AppWindow.Size.Height / (currentDpi / 96d); } set { - this.SetWindowSize(AppWindow.Size.Width, value); + this.SetWindowSize(Width, value); } } diff --git a/src/WinUIEx/WindowExtensions.cs b/src/WinUIEx/WindowExtensions.cs index d80a2e6..153893d 100644 --- a/src/WinUIEx/WindowExtensions.cs +++ b/src/WinUIEx/WindowExtensions.cs @@ -23,7 +23,7 @@ public static partial class WindowExtensions /// /// Learn more about this API from docs.microsoft.com. /// - public static uint GetDpiForWindow(this Microsoft.UI.Xaml.Window window) => (uint?)(window.Content?.XamlRoot?.RasterizationScale * 96f) ?? HwndExtensions.GetDpiForWindow(window.GetWindowHandle()); + public static uint GetDpiForWindow(this Microsoft.UI.Xaml.Window window) => HwndExtensions.GetDpiForWindow(window.GetWindowHandle()); /// Brings the thread that created the specified window into the foreground and activates the window. /// @@ -142,13 +142,15 @@ public static void CenterOnScreen(this Microsoft.UI.Xaml.Window window, double? /// Positions and resizes the window /// /// Window - /// Left side of the window in device independent pixels - /// Top side of the window in device independent pixels + /// Left side of the window + /// Top side of the window /// Width of the window in device independent pixels, or null if keeping the current size /// Height of the window in device independent pixels, or null if keeping the current size public static void MoveAndResize(this Microsoft.UI.Xaml.Window window, double x, double y, double width, double height) - => window.GetAppWindow().MoveAndResize(new Windows.Graphics.RectInt32((int)x, (int)y, (int)width, (int)height)); // TODO: Adjust for dpi - //=> HwndExtensions.SetWindowPositionAndSize(window.GetWindowHandle(), x, y, width, height); + { + var scale = HwndExtensions.GetDpiForWindow(window.GetWindowHandle()) / 96f; + window.GetAppWindow().MoveAndResize(new Windows.Graphics.RectInt32((int)x, (int)y, (int)(width * scale), (int)(height * scale))); + } /// /// Sets the width and height of the window in device-independent pixels. @@ -157,7 +159,10 @@ public static void MoveAndResize(this Microsoft.UI.Xaml.Window window, double x, /// Width of the window in device-independent units. /// Height of the window in device-independent units. public static void SetWindowSize(this Microsoft.UI.Xaml.Window window, double width, double height) - => window.GetAppWindow().Resize(new Windows.Graphics.SizeInt32((int)width, (int)height)); + { + var scale = HwndExtensions.GetDpiForWindow(window.GetWindowHandle()) / 96f; + window.GetAppWindow().Resize(new Windows.Graphics.SizeInt32((int)(width * scale), (int)(height * scale))); + } /// /// Sets the window presenter kind used.