diff --git a/src/Wpf.Ui/Appearance/WindowBackgroundManager.cs b/src/Wpf.Ui/Appearance/WindowBackgroundManager.cs index 84f9bc8da..769e888bc 100644 --- a/src/Wpf.Ui/Appearance/WindowBackgroundManager.cs +++ b/src/Wpf.Ui/Appearance/WindowBackgroundManager.cs @@ -100,6 +100,7 @@ WindowBackdropType backdrop } _ = WindowBackdrop.ApplyBackdrop(window, backdrop); + if (applicationTheme is ApplicationTheme.Dark) { ApplyDarkThemeToWindow(window); @@ -109,6 +110,8 @@ WindowBackdropType backdrop RemoveDarkThemeFromWindow(window); } + _ = WindowBackdrop.RemoveTitlebarBackground(window); + foreach (object? subWindow in window.OwnedWindows) { if (subWindow is Window windowSubWindow) @@ -123,6 +126,8 @@ WindowBackdropType backdrop { RemoveDarkThemeFromWindow(windowSubWindow); } + + _ = WindowBackdrop.RemoveTitlebarBackground(window); } } } diff --git a/src/Wpf.Ui/Controls/FluentWindow/FluentWindow.cs b/src/Wpf.Ui/Controls/FluentWindow/FluentWindow.cs index c8cc3bea8..9d4905211 100644 --- a/src/Wpf.Ui/Controls/FluentWindow/FluentWindow.cs +++ b/src/Wpf.Ui/Controls/FluentWindow/FluentWindow.cs @@ -199,6 +199,8 @@ protected virtual void OnBackdropTypeChanged(WindowBackdropType oldValue, Window if (WindowBackdrop.IsSupported(newValue) && WindowBackdrop.RemoveBackground(this)) { _ = WindowBackdrop.ApplyBackdrop(this, newValue); + + _ = WindowBackdrop.RemoveTitlebarBackground(this); } } diff --git a/src/Wpf.Ui/Controls/VirtualizingWrapPanel/VirtualizingWrapPanel.cs b/src/Wpf.Ui/Controls/VirtualizingWrapPanel/VirtualizingWrapPanel.cs index 0507f36ea..1a58d4723 100644 --- a/src/Wpf.Ui/Controls/VirtualizingWrapPanel/VirtualizingWrapPanel.cs +++ b/src/Wpf.Ui/Controls/VirtualizingWrapPanel/VirtualizingWrapPanel.cs @@ -425,7 +425,8 @@ protected override ItemRange UpdateItemRange() int rowCountInCacheBefore = (int)(cacheBeforeInPixel / GetHeight(ChildSize)); int rowCountInCacheAfter = ( - (int)Math.Ceiling( + (int) + Math.Ceiling( (offsetInPixel + viewportHeight + cacheAfterInPixel) / GetHeight(ChildSize) ) ) - (int)Math.Ceiling((offsetInPixel + viewportHeight) / GetHeight(ChildSize)); diff --git a/src/Wpf.Ui/Controls/Window/WindowBackdrop.cs b/src/Wpf.Ui/Controls/Window/WindowBackdrop.cs index 582d03cd7..a1cc1c2d2 100644 --- a/src/Wpf.Ui/Controls/Window/WindowBackdrop.cs +++ b/src/Wpf.Ui/Controls/Window/WindowBackdrop.cs @@ -38,7 +38,7 @@ public static bool IsSupported(WindowBackdropType backdropType) /// The window to which the backdrop effect will be applied. /// The type of backdrop effect to apply. Determines the visual appearance of the window's backdrop. /// if the operation was successful; otherwise, . - public static bool ApplyBackdrop(System.Windows.Window window, WindowBackdropType backdropType) + public static bool ApplyBackdrop(System.Windows.Window? window, WindowBackdropType backdropType) { if (window is null) { @@ -216,6 +216,40 @@ public static bool RemoveBackground(System.Windows.Window? window) return true; } + public static bool RemoveTitlebarBackground(System.Windows.Window? window) + { + if (window is null) + { + return false; + } + + IntPtr windowHandle = new WindowInteropHelper(window).Handle; + + if (windowHandle == IntPtr.Zero) + { + return false; + } + + HwndSource? windowSource = HwndSource.FromHwnd(windowHandle); + + // Remove background from client area + if (windowSource?.Handle != IntPtr.Zero && windowSource?.CompositionTarget != null) + { + // NOTE: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute + // Specifying DWMWA_COLOR_DEFAULT (value 0xFFFFFFFF) for the color will reset the window back to using the system's default behavior for the caption color. + uint titlebarPvAttribute = 0xFFFFFFFE; + + Dwmapi.DwmSetWindowAttribute( + windowSource.Handle, + Dwmapi.DWMWINDOWATTRIBUTE.DWMWA_CAPTION_COLOR, + ref titlebarPvAttribute, + Marshal.SizeOf(typeof(uint)) + ); + } + + return true; + } + private static bool ApplyDwmwWindowAttrubute(IntPtr hWnd, Dwmapi.DWMSBT dwmSbt) { if (hWnd == IntPtr.Zero) @@ -228,7 +262,7 @@ private static bool ApplyDwmwWindowAttrubute(IntPtr hWnd, Dwmapi.DWMSBT dwmSbt) return false; } - var backdropPvAttribute = (int)dwmSbt; + int backdropPvAttribute = (int)dwmSbt; var dwmApiResult = Dwmapi.DwmSetWindowAttribute( hWnd, diff --git a/src/Wpf.Ui/Interop/Dwmapi.cs b/src/Wpf.Ui/Interop/Dwmapi.cs index f1a090711..adf6a9618 100644 --- a/src/Wpf.Ui/Interop/Dwmapi.cs +++ b/src/Wpf.Ui/Interop/Dwmapi.cs @@ -619,6 +619,22 @@ public static extern int DwmSetWindowAttribute( [In] int cbAttribute ); + /// + /// Sets the value of Desktop Window Manager (DWM) non-client rendering attributes for a window. + /// + /// The handle to the window for which the attribute value is to be set. + /// A flag describing which value to set, specified as a value of the DWMWINDOWATTRIBUTE enumeration. + /// A pointer to an object containing the attribute value to set. + /// The size, in bytes, of the attribute value being set via the pvAttribute parameter. + /// If the function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [DllImport(Libraries.Dwmapi)] + public static extern int DwmSetWindowAttribute( + [In] IntPtr hWnd, + [In] DWMWINDOWATTRIBUTE dwAttribute, + [In] ref uint pvAttribute, + [In] int cbAttribute + ); + /// /// Retrieves the current value of a specified Desktop Window Manager (DWM) attribute applied to a window. For programming guidance, and code examples, see Controlling non-client region rendering. /// diff --git a/src/Wpf.Ui/Interop/UnsafeNativeMethods.cs b/src/Wpf.Ui/Interop/UnsafeNativeMethods.cs index a3fc2421a..e73401cca 100644 --- a/src/Wpf.Ui/Interop/UnsafeNativeMethods.cs +++ b/src/Wpf.Ui/Interop/UnsafeNativeMethods.cs @@ -376,9 +376,7 @@ public static Color GetDwmColor() return Color.FromArgb(255, values[2], values[1], values[0]); } - catch - { - } + catch { } } } diff --git a/src/Wpf.Ui/Markup/Design.cs b/src/Wpf.Ui/Markup/Design.cs index 5dbb316f1..6a6966659 100644 --- a/src/Wpf.Ui/Markup/Design.cs +++ b/src/Wpf.Ui/Markup/Design.cs @@ -28,10 +28,12 @@ public static class Design /// private static bool InDesignMode => _inDesignMode ??= - (bool)DependencyPropertyDescriptor + (bool) + DependencyPropertyDescriptor .FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(FrameworkElement)) .Metadata.DefaultValue - || System.Diagnostics.Process.GetCurrentProcess() + || System + .Diagnostics.Process.GetCurrentProcess() .ProcessName.StartsWith(DesignProcessName, StringComparison.Ordinal); public static readonly DependencyProperty BackgroundProperty = DependencyProperty.RegisterAttached( diff --git a/src/Wpf.Ui/UiApplication.cs b/src/Wpf.Ui/UiApplication.cs index 4ec6f2cea..b12c0b7a9 100644 --- a/src/Wpf.Ui/UiApplication.cs +++ b/src/Wpf.Ui/UiApplication.cs @@ -36,8 +36,8 @@ public UiApplication(Application application) _application = application; System.Diagnostics.Debug.WriteLine( - $"INFO | {typeof(UiApplication)} application is {_application}", - "Wpf.Ui" + $"INFO | {typeof(UiApplication)} application is {_application}", + "Wpf.Ui" ); } @@ -95,14 +95,11 @@ public ResourceDictionary Resources _resources.MergedDictionaries.Add(themesDictionary); _resources.MergedDictionaries.Add(controlsDictionary); } - catch - { - } + catch { } } return _application?.Resources ?? _resources; } - set { if (_application is not null) @@ -132,8 +129,10 @@ public void Shutdown() private static bool ApplicationHasResources(Application application) { - return application.Resources.MergedDictionaries - .Where(e => e.Source is not null) - .Any(e => e.Source.ToString().ToLower().Contains(Appearance.ApplicationThemeManager.LibraryNamespace)); + return application + .Resources.MergedDictionaries.Where(e => e.Source is not null) + .Any(e => + e.Source.ToString().ToLower().Contains(Appearance.ApplicationThemeManager.LibraryNamespace) + ); } }