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..2341e44 100644
--- a/EleCho.WpfSuite.Helpers/Helpers/WindowOption.cs
+++ b/EleCho.WpfSuite.Helpers/Helpers/WindowOption.cs
@@ -89,6 +89,40 @@ public static void SetBackdrop(DependencyObject obj, WindowBackdrop value)
}
+ ///
+ /// Get value of IsBackdropAlwaysActive property
+ ///
+ ///
+ ///
+ ///
+ /// This property controls whether the window backdrop (Mica/Acrylic) remains active when the window loses focus.
+ /// By default (false), Windows automatically deactivates the backdrop when the window is not focused.
+ /// When set to true, the backdrop will remain active even when the window loses focus.
+ /// This property is primarily designed for Window objects, but also supports Popup, ToolTip, ContextMenu, and MenuItem for consistency with other WindowOption properties.
+ ///
+ [AttachedPropertyBrowsableForType(typeof(Window))]
+ public static bool GetIsBackdropAlwaysActive(DependencyObject obj)
+ {
+ return (bool)obj.GetValue(IsBackdropAlwaysActiveProperty);
+ }
+
+ ///
+ /// Set value of IsBackdropAlwaysActive property
+ ///
+ ///
+ ///
+ ///
+ /// This property controls whether the window backdrop (Mica/Acrylic) remains active when the window loses focus.
+ /// By default (false), Windows automatically deactivates the backdrop when the window is not focused.
+ /// When set to true, the backdrop will remain active even when the window loses focus.
+ /// This property is primarily designed for Window objects, but also supports Popup, ToolTip, ContextMenu, and MenuItem for consistency with other WindowOption properties.
+ ///
+ public static void SetIsBackdropAlwaysActive(DependencyObject obj, bool value)
+ {
+ obj.SetValue(IsBackdropAlwaysActiveProperty, value);
+ }
+
+
///
/// Get value of Corner property
///
@@ -398,6 +432,18 @@ 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
+ ///
+ ///
+ /// Controls whether the window backdrop (Mica/Acrylic) remains active when the window loses focus.
+ /// Default value is false, meaning the backdrop will be deactivated when the window loses focus (standard Windows behavior).
+ /// When set to true, the backdrop will remain active even when the window is not focused.
+ /// This property requires Windows 11 Build 22621 or later.
+ ///
+ public static readonly DependencyProperty IsBackdropAlwaysActiveProperty =
+ DependencyProperty.RegisterAttached("IsBackdropAlwaysActive", typeof(bool), typeof(WindowOption), new FrameworkPropertyMetadata(false, OnIsBackdropAlwaysActiveChanged));
+
///
/// The DependencyProperty of Corner property
///
@@ -1010,6 +1056,54 @@ 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);
+ }
+
+ // Always remove the event handler first to prevent duplicates
+ if (d is Window window)
+ {
+ window.SourceInitialized -= EventHandlerApplyIsBackdropAlwaysActive;
+ if (isAlwaysActive)
+ window.SourceInitialized += EventHandlerApplyIsBackdropAlwaysActive;
+ }
+ else if (d is Popup popup)
+ {
+ popup.Opened -= EventHandlerApplyIsBackdropAlwaysActive;
+ if (isAlwaysActive)
+ popup.Opened += EventHandlerApplyIsBackdropAlwaysActive;
+ }
+ else if (d is ToolTip toolTip)
+ {
+ toolTip.Opened -= EventHandlerApplyIsBackdropAlwaysActive;
+ if (isAlwaysActive)
+ toolTip.Opened += EventHandlerApplyIsBackdropAlwaysActive;
+ }
+ else if (d is ContextMenu contextMenu)
+ {
+ contextMenu.Opened -= EventHandlerApplyIsBackdropAlwaysActive;
+ if (isAlwaysActive)
+ contextMenu.Opened += EventHandlerApplyIsBackdropAlwaysActive;
+ }
+ else if (d is MenuItem menuItem)
+ {
+ menuItem.SubmenuOpened -= EventHandlerApplyIsBackdropAlwaysActive;
+ if (isAlwaysActive)
+ menuItem.SubmenuOpened += EventHandlerApplyIsBackdropAlwaysActive;
+ }
+ else if (d is FrameworkElement element)
+ {
+ element.Loaded -= EventHandlerApplyIsBackdropAlwaysActive;
+ if (isAlwaysActive)
+ element.Loaded += EventHandlerApplyIsBackdropAlwaysActive;
+ }
+ }
+
private static void OnCornerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var corner = GetCorner(d);
@@ -1988,6 +2082,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 +2528,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 &&
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WpfTest/Tests/BackdropAlwaysActiveTestWindow.xaml.cs b/WpfTest/Tests/BackdropAlwaysActiveTestWindow.xaml.cs
new file mode 100644
index 0000000..7364f0c
--- /dev/null
+++ b/WpfTest/Tests/BackdropAlwaysActiveTestWindow.xaml.cs
@@ -0,0 +1,21 @@
+using System.Windows;
+
+namespace WpfTest.Tests
+{
+ ///
+ /// Interaction logic for BackdropAlwaysActiveTestWindow.xaml
+ ///
+ public partial class BackdropAlwaysActiveTestWindow : Window
+ {
+ public BackdropAlwaysActiveTestWindow()
+ {
+ InitializeComponent();
+ }
+
+ private void OpenNormalWindow_Click(object sender, RoutedEventArgs e)
+ {
+ var normalWindow = new BackdropNormalTestWindow();
+ normalWindow.Show();
+ }
+ }
+}
diff --git a/WpfTest/Tests/BackdropNormalTestWindow.xaml b/WpfTest/Tests/BackdropNormalTestWindow.xaml
new file mode 100644
index 0000000..3e7de07
--- /dev/null
+++ b/WpfTest/Tests/BackdropNormalTestWindow.xaml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WpfTest/Tests/BackdropNormalTestWindow.xaml.cs b/WpfTest/Tests/BackdropNormalTestWindow.xaml.cs
new file mode 100644
index 0000000..4f7294d
--- /dev/null
+++ b/WpfTest/Tests/BackdropNormalTestWindow.xaml.cs
@@ -0,0 +1,15 @@
+using System.Windows;
+
+namespace WpfTest.Tests
+{
+ ///
+ /// Interaction logic for BackdropNormalTestWindow.xaml
+ ///
+ public partial class BackdropNormalTestWindow : Window
+ {
+ public BackdropNormalTestWindow()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/WpfTest/Tests/WindowCompositionTest.xaml b/WpfTest/Tests/WindowCompositionTest.xaml
index 8fe63a1..71044ab 100644
--- a/WpfTest/Tests/WindowCompositionTest.xaml
+++ b/WpfTest/Tests/WindowCompositionTest.xaml
@@ -39,6 +39,15 @@
+
+
+
+
+
+
diff --git a/WpfTest/Tests/WindowCompositionTest.xaml.cs b/WpfTest/Tests/WindowCompositionTest.xaml.cs
index 33b616f..8b3219a 100644
--- a/WpfTest/Tests/WindowCompositionTest.xaml.cs
+++ b/WpfTest/Tests/WindowCompositionTest.xaml.cs
@@ -75,5 +75,11 @@ public void OpenDarkCustomAcrylicWindow()
window.Foreground = new SolidColorBrush(Color.FromRgb(214, 214, 214));
window.Show();
}
+
+ [RelayCommand]
+ public void OpenBackdropAlwaysActiveTestWindow()
+ {
+ new BackdropAlwaysActiveTestWindow().Show();
+ }
}
}