From 5bce1ab2f8bd88a84983f24c653f0a0f18b9a6e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:21:08 +0000 Subject: [PATCH 1/5] Initial plan From 8f0c47e3176e7a7db4bf42e930d5b3caa97960db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:26:10 +0000 Subject: [PATCH 2/5] Add IsBackdropAlwaysActive property to control backdrop behavior when window loses focus Co-authored-by: emako <24737061+emako@users.noreply.github.com> --- .../Helpers/WindowOption.NativeMethods.cs | 1 + .../Helpers/WindowOption.cs | 111 ++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/EleCho.WpfSuite.Helpers/Helpers/WindowOption.NativeMethods.cs b/EleCho.WpfSuite.Helpers/Helpers/WindowOption.NativeMethods.cs index 7287c75..3fcf9c9 100644 --- a/EleCho.WpfSuite.Helpers/Helpers/WindowOption.NativeMethods.cs +++ b/EleCho.WpfSuite.Helpers/Helpers/WindowOption.NativeMethods.cs @@ -160,6 +160,7 @@ public enum DwmWindowAttribute TEXT_COLOR, VISIBLE_FRAME_BORDER_THICKNESS, SYSTEMBACKDROP_TYPE, + SYSTEMBACKDROP_ALWAYS_ACTIVE, LAST } diff --git a/EleCho.WpfSuite.Helpers/Helpers/WindowOption.cs b/EleCho.WpfSuite.Helpers/Helpers/WindowOption.cs index dee0476..b0b4b6e 100644 --- a/EleCho.WpfSuite.Helpers/Helpers/WindowOption.cs +++ b/EleCho.WpfSuite.Helpers/Helpers/WindowOption.cs @@ -89,6 +89,28 @@ public static void SetBackdrop(DependencyObject obj, WindowBackdrop value) } + /// + /// Get value of IsBackdropAlwaysActive property + /// + /// + /// + [AttachedPropertyBrowsableForType(typeof(Window))] + public static bool GetIsBackdropAlwaysActive(DependencyObject obj) + { + return (bool)obj.GetValue(IsBackdropAlwaysActiveProperty); + } + + /// + /// Set value of IsBackdropAlwaysActive property + /// + /// + /// + public static void SetIsBackdropAlwaysActive(DependencyObject obj, bool value) + { + obj.SetValue(IsBackdropAlwaysActiveProperty, value); + } + + /// /// Get value of Corner property /// @@ -398,6 +420,12 @@ public static void SetIsCaption(DependencyObject obj, bool value) public static readonly DependencyProperty BackdropProperty = DependencyProperty.RegisterAttached("Backdrop", typeof(WindowBackdrop), typeof(WindowOption), new FrameworkPropertyMetadata(WindowBackdrop.Auto, OnBackdropChanged)); + /// + /// The DependencyProperty of IsBackdropAlwaysActive property + /// + public static readonly DependencyProperty IsBackdropAlwaysActiveProperty = + DependencyProperty.RegisterAttached("IsBackdropAlwaysActive", typeof(bool), typeof(WindowOption), new FrameworkPropertyMetadata(false, OnIsBackdropAlwaysActiveChanged)); + /// /// The DependencyProperty of Corner property /// @@ -1010,6 +1038,71 @@ backdrop is not WindowBackdrop.Auto && } } + private static void OnIsBackdropAlwaysActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var isAlwaysActive = GetIsBackdropAlwaysActive(d); + + if (GetWindowHwndSource(d) is HwndSource hwndSource) + { + ApplyIsBackdropAlwaysActive(hwndSource, isAlwaysActive); + } + + if (isAlwaysActive) + { + if (d is Window window) + { + window.SourceInitialized += EventHandlerApplyIsBackdropAlwaysActive; + } + else if (d is Popup popup) + { + popup.Opened += EventHandlerApplyIsBackdropAlwaysActive; + } + else if (d is ToolTip toolTip) + { + toolTip.Opened += EventHandlerApplyIsBackdropAlwaysActive; + } + else if (d is ContextMenu contextMenu) + { + contextMenu.Opened += EventHandlerApplyIsBackdropAlwaysActive; + } + else if (d is MenuItem menuItem) + { + menuItem.SubmenuOpened += EventHandlerApplyIsBackdropAlwaysActive; + } + else if (d is FrameworkElement element) + { + element.Loaded += EventHandlerApplyIsBackdropAlwaysActive; + } + } + else + { + if (d is Window window) + { + window.SourceInitialized -= EventHandlerApplyIsBackdropAlwaysActive; + } + else if (d is Popup popup) + { + popup.Opened -= EventHandlerApplyIsBackdropAlwaysActive; + } + else if (d is ToolTip toolTip) + { + toolTip.Opened -= EventHandlerApplyIsBackdropAlwaysActive; + } + else if (d is ContextMenu contextMenu) + { + contextMenu.Opened -= EventHandlerApplyIsBackdropAlwaysActive; + } + else if (d is MenuItem menuItem) + { + menuItem.SubmenuOpened -= EventHandlerApplyIsBackdropAlwaysActive; + } + else if (d is FrameworkElement element) + { + element.Loaded -= EventHandlerApplyIsBackdropAlwaysActive; + } + } + } + private static void OnCornerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var corner = GetCorner(d); @@ -1988,6 +2081,17 @@ private static unsafe void ApplyCorner(HwndSource hwndSource, WindowCorner corne DwmSetWindowAttribute(handle, DwmWindowAttribute.WINDOW_CORNER_PREFERENCE, (nint)(void*)&corner, (uint)sizeof(WindowCorner)); } + private static unsafe void ApplyIsBackdropAlwaysActive(HwndSource hwndSource, bool isAlwaysActive) + { + // this api is only available on windows 11 22621 + if (s_versionCurrentWindows < s_versionWindows11_22621) + return; + + var handle = hwndSource.Handle; + + DwmSetWindowAttribute(handle, DwmWindowAttribute.SYSTEMBACKDROP_ALWAYS_ACTIVE, (nint)(void*)&isAlwaysActive, (uint)sizeof(bool)); + } + private static unsafe void ApplyCaptionColor(HwndSource hwndSource, WindowOptionColor color) { // this api is only available on windows 11 22000 @@ -2423,6 +2527,13 @@ private static void EventHandlerApplyCorner(object? sender, EventArgs e) ApplyCorner(hwndSource, GetCorner(d)); } + private static void EventHandlerApplyIsBackdropAlwaysActive(object? sender, EventArgs e) + { + if (sender is DependencyObject d && + GetWindowHwndSource(d) is HwndSource hwndSource) + ApplyIsBackdropAlwaysActive(hwndSource, GetIsBackdropAlwaysActive(d)); + } + private static void EventHandlerApplyCaptionColor(object? sender, EventArgs e) { if (sender is DependencyObject d && From 478131744aecfe66bde249a2690e585509ecd58c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:29:53 +0000 Subject: [PATCH 3/5] Add test windows for IsBackdropAlwaysActive property Co-authored-by: emako <24737061+emako@users.noreply.github.com> --- .../Tests/BackdropAlwaysActiveTestWindow.xaml | 69 +++++++++++++++++++ .../BackdropAlwaysActiveTestWindow.xaml.cs | 21 ++++++ WpfTest/Tests/BackdropNormalTestWindow.xaml | 59 ++++++++++++++++ .../Tests/BackdropNormalTestWindow.xaml.cs | 15 ++++ WpfTest/Tests/WindowCompositionTest.xaml | 9 +++ WpfTest/Tests/WindowCompositionTest.xaml.cs | 6 ++ 6 files changed, 179 insertions(+) create mode 100644 WpfTest/Tests/BackdropAlwaysActiveTestWindow.xaml create mode 100644 WpfTest/Tests/BackdropAlwaysActiveTestWindow.xaml.cs create mode 100644 WpfTest/Tests/BackdropNormalTestWindow.xaml create mode 100644 WpfTest/Tests/BackdropNormalTestWindow.xaml.cs diff --git a/WpfTest/Tests/BackdropAlwaysActiveTestWindow.xaml b/WpfTest/Tests/BackdropAlwaysActiveTestWindow.xaml new file mode 100644 index 0000000..8153edc --- /dev/null +++ b/WpfTest/Tests/BackdropAlwaysActiveTestWindow.xaml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +