From 011d0a2868c87620a60956bd34b37dc423145cb0 Mon Sep 17 00:00:00 2001 From: Foysal Ahamed Date: Sat, 25 Oct 2025 10:59:01 +0600 Subject: [PATCH] Fix WindowChrome on Windows 10 --- .../WPFGallery/MainWindow.xaml.cs | 84 +++++++++++++++---- 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/Sample Applications/WPFGallery/MainWindow.xaml.cs b/Sample Applications/WPFGallery/MainWindow.xaml.cs index 56a3fb68..6a50a000 100644 --- a/Sample Applications/WPFGallery/MainWindow.xaml.cs +++ b/Sample Applications/WPFGallery/MainWindow.xaml.cs @@ -1,6 +1,8 @@ -using System.Windows.Automation; +using System.Runtime.InteropServices; +using System.Windows.Automation; using System.Windows.Automation.Peers; using System.Windows.Controls.Primitives; +using System.Windows.Interop; using System.Windows.Navigation; using System.Windows.Shell; using Microsoft.Win32; @@ -41,8 +43,7 @@ public MainWindow(MainWindowViewModel viewModel, IServiceProvider serviceProvide GlassFrameThickness = new Thickness(-1), ResizeBorderThickness = ResizeMode == ResizeMode.NoResize ? default : new Thickness(4), UseAeroCaptionButtons = true, - NonClientFrameEdges = SystemParameters.HighContrast ? NonClientFrameEdges.None : - NonClientFrameEdges.Right | NonClientFrameEdges.Bottom | NonClientFrameEdges.Left + NonClientFrameEdges = GetPreferredNonClientFrameEdges() } ); @@ -50,6 +51,7 @@ public MainWindow(MainWindowViewModel viewModel, IServiceProvider serviceProvide this.StateChanged += (s, e) => UpdateMainWindowVisuals(); this.Activated += (s, e) => UpdateMainWindowVisuals(); this.Deactivated += (s, e) => UpdateMainWindowVisuals(); + this.Loaded += (_, _) => ApplyWindowDarkMode(); } private void UpdateWindowBackground() @@ -99,29 +101,26 @@ private void UpdateMainWindowVisuals() } UpdateTitleBarButtonsVisibility(); + bool shouldForceEdgeNone = ShouldForceNonClientFrameEdgesNone(); if(SystemParameters.HighContrast == true) { HighContrastBorder.SetResourceReference(BorderBrushProperty, IsActive ? SystemColors.ActiveCaptionBrushKey : SystemColors.InactiveCaptionBrushKey); HighContrastBorder.BorderThickness = new Thickness(8, 1, 8, 8); - - WindowChrome wc = WindowChrome.GetWindowChrome(this); - if(wc is not null) - { - wc.NonClientFrameEdges = NonClientFrameEdges.None; - } } else { HighContrastBorder.BorderBrush = Brushes.Transparent; HighContrastBorder.BorderThickness = new Thickness(0); + } - var wc = WindowChrome.GetWindowChrome(this); - if(wc is not null) - { - wc.NonClientFrameEdges = NonClientFrameEdges.Right | NonClientFrameEdges.Bottom | NonClientFrameEdges.Left; - } + var wc = WindowChrome.GetWindowChrome(this); + if (wc is not null) + { + wc.NonClientFrameEdges = shouldForceEdgeNone + ? NonClientFrameEdges.None + : NonClientFrameEdges.Right | NonClientFrameEdges.Bottom | NonClientFrameEdges.Left; } } @@ -254,4 +253,61 @@ private void SettingsButton_Click(object sender, RoutedEventArgs e) "ButtonClickedActivity" ); } + + private static NonClientFrameEdges GetPreferredNonClientFrameEdges() + { + return ShouldForceNonClientFrameEdgesNone() + ? NonClientFrameEdges.None + : NonClientFrameEdges.Right | NonClientFrameEdges.Bottom | NonClientFrameEdges.Left; + } + + private static bool ShouldForceNonClientFrameEdgesNone() + { + return SystemParameters.HighContrast == true || IsWindows10WithLegacyChromeBehavior(); + } + + private static bool IsWindows10WithLegacyChromeBehavior() + { + return OperatingSystem.IsWindows() && + OperatingSystem.IsWindowsVersionAtLeast(10) && + !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000); + } + + private void ApplyWindowDarkMode() + { + if (!IsImmersiveDarkModeSupported()) + { + return; + } + + var hwnd = new WindowInteropHelper(this).Handle; + if (hwnd == IntPtr.Zero) + { + return; + } + + int darkModeEnabled = 1; + try + { + _ = DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, ref darkModeEnabled, sizeof(int)); + } + catch (DllNotFoundException) + { + // dwmapi.dll is unavailable on this system. + } + catch (EntryPointNotFoundException) + { + // The immersive dark mode attribute is not supported. + } + } + + private static bool IsImmersiveDarkModeSupported() + { + return OperatingSystem.IsWindows() && OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17763); + } + + [DllImport("dwmapi.dll")] + private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize); + + private const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20; } \ No newline at end of file