diff --git a/src/Avalonia.Controls/Chrome/WindowDrawnDecorations.cs b/src/Avalonia.Controls/Chrome/WindowDrawnDecorations.cs index d68e2c6f5e..4e739649a9 100644 --- a/src/Avalonia.Controls/Chrome/WindowDrawnDecorations.cs +++ b/src/Avalonia.Controls/Chrome/WindowDrawnDecorations.cs @@ -506,24 +506,23 @@ public class WindowDrawnDecorations : StyledElement private void OnMinimizeButtonClick(object? sender, Interactivity.RoutedEventArgs e) { - _hostWindow?.TrySetWindowState(WindowState.Minimized); + _hostWindow?.WindowState = WindowState.Minimized; e.Handled = true; } private void OnMaximizeButtonClick(object? sender, Interactivity.RoutedEventArgs e) { - _hostWindow?.TrySetWindowState(_hostWindow.EffectivePlatformWindowState == WindowState.Maximized + _hostWindow?.WindowState = _hostWindow.WindowState == WindowState.Maximized ? WindowState.Normal - : WindowState.Maximized); + : WindowState.Maximized; e.Handled = true; } private void OnFullScreenButtonClick(object? sender, Interactivity.RoutedEventArgs e) { - if (_hostWindow != null) - _hostWindow?.TrySetWindowState(_hostWindow.EffectivePlatformWindowState == WindowState.FullScreen + _hostWindow?.WindowState = _hostWindow.WindowState == WindowState.FullScreen ? WindowState.Normal - : WindowState.FullScreen); + : WindowState.FullScreen; e.Handled = true; } @@ -531,7 +530,7 @@ public class WindowDrawnDecorations : StyledElement { if (_maximizeButton == null) return; - _maximizeButton.IsEnabled = _hostWindow?.EffectivePlatformWindowState switch + _maximizeButton.IsEnabled = _hostWindow?.WindowState switch { WindowState.Maximized or WindowState.FullScreen => _hostWindow.CanResize, WindowState.Normal => _hostWindow.CanMaximize, @@ -550,7 +549,7 @@ public class WindowDrawnDecorations : StyledElement { if (_fullScreenButton == null) return; - _fullScreenButton.IsEnabled = _hostWindow?.EffectivePlatformWindowState == WindowState.FullScreen + _fullScreenButton.IsEnabled = _hostWindow?.WindowState == WindowState.FullScreen ? _hostWindow.CanResize : _hostWindow?.CanMaximize ?? true; } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index a467357f1e..81fdad9934 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -157,24 +157,13 @@ namespace Avalonia.Controls public static readonly StyledProperty ClosingBehaviorProperty = AvaloniaProperty.Register(nameof(ClosingBehavior)); - /// - /// Represents the current window state (normal, minimized, maximized) or window state set by data binding. - /// Can temporally have a value that had no effect on the window state whatsoever if the value - /// was set by data binding and the platform refused to apply it or delayed applying it. - /// You have no means to detect if the value of this property currently has a temporary value, - /// this is done by design to keep this property bindable. - /// - public static readonly StyledProperty WindowStateProperty = - AvaloniaProperty.Register(nameof(WindowState)); - - - private WindowState _effectivePlatformWindowStatePropertyCache; /// /// Represents the currently effective window state (normal, minimized, maximized) /// - public static readonly DirectProperty EffectivePlatformWindowStateProperty = AvaloniaProperty.RegisterDirect( - "EffectivePlatformWindowState", o => o.EffectivePlatformWindowState); - + public static readonly DirectProperty WindowStateProperty = + AvaloniaProperty.RegisterDirect( + "EffectivePlatformWindowState", o => o.WindowState, + (o, v) => o.WindowState = v); /// /// Defines the property. @@ -271,8 +260,7 @@ namespace Avalonia.Controls CreatePlatformImplBinding(CanMinimizeProperty, canMinimize => PlatformImpl!.SetCanMinimize(canMinimize)); CreatePlatformImplBinding(CanMaximizeProperty, canMaximize => PlatformImpl!.SetCanMaximize(canMaximize)); CreatePlatformImplBinding(ShowInTaskbarProperty, show => PlatformImpl!.ShowTaskbarIcon(show)); - - CreatePlatformImplBinding(WindowStateProperty, TrySetWindowState); + CreatePlatformImplBinding(ExtendClientAreaToDecorationsHintProperty, hint => PlatformImpl!.SetExtendClientAreaToDecorationsHint(hint)); CreatePlatformImplBinding(ExtendClientAreaTitleBarHeightHintProperty, height => PlatformImpl!.SetExtendClientAreaTitleBarHeightHint(height)); @@ -419,22 +407,26 @@ namespace Avalonia.Controls set => SetValue(ClosingBehaviorProperty, value); } + private WindowState _windowStateForPropertyNotifications; /// - /// Represents the current window state (normal, minimized, maximized) or window state set by data binding. - /// Can temporally have a value that had no effect on the window state whatsoever if the value - /// was set by data binding and the platform refused to apply it or delayed applying it. - /// To get the effective window state use + /// Represents the currently effective window state (normal, minimized, maximized) /// public WindowState WindowState { - get => GetValue(WindowStateProperty); - set => SetValue(WindowStateProperty, value); + get => PlatformImpl?.WindowState ?? default; + set + { + if (PlatformImpl != null) + { + PlatformImpl.WindowState = value; + var oldValue = _windowStateForPropertyNotifications; + _windowStateForPropertyNotifications = PlatformImpl.WindowState; + // If the request was refused - trigger a synthetic property change + if (PlatformImpl.WindowState != value) + RaisePropertyChanged(WindowStateProperty, oldValue, _windowStateForPropertyNotifications); + } + } } - - /// - /// Represents the currently effective window state (normal, minimized, maximized) - /// - public WindowState EffectivePlatformWindowState => PlatformImpl?.WindowState ?? WindowState; /// /// Enables or disables resizing of the window. @@ -641,12 +633,7 @@ namespace Avalonia.Controls private void HandleWindowStateChanged(WindowState state) { -#pragma warning disable CS0618 // Type or member is obsolete - SetAndRaise(EffectivePlatformWindowStateProperty, ref _effectivePlatformWindowStatePropertyCache, - EffectivePlatformWindowState); - - WindowState = state; -#pragma warning restore CS0618 // Type or member is obsolete + SetAndRaise(WindowStateProperty, ref _windowStateForPropertyNotifications, state); if (state == WindowState.Minimized) { @@ -660,28 +647,6 @@ namespace Avalonia.Controls // Update decoration parts and fullscreen popover state for the new window state UpdateDrawnDecorationParts(); } - - private void HandleBindableWindowStateChanged(WindowState state) - { - if (PlatformImpl?.WindowState == state) - return; - PlatformImpl?.WindowState = state; - if(PlatformImpl == null || PlatformImpl.WindowState == state) - return; - // Request failed, reset WindowState to the effective value -#pragma warning disable CS0618 // Type or member is obsolete - WindowState = PlatformImpl.WindowState; -#pragma warning restore CS0618 // Type or member is obsolete - } - - /// - /// Attempt to transition the window state to the specified state. The request might be delayed or - /// ignored by the underlying platform - /// - public void TrySetWindowState(WindowState state) - { - PlatformImpl?.WindowState = state; - } protected virtual void ExtendClientAreaToDecorationsChanged(bool isExtended) { @@ -698,7 +663,7 @@ namespace Avalonia.Controls // Detect forced mode: platform needs managed decorations but app hasn't opted in _isForcedDecorationMode = parts != null && !IsExtendedIntoWindowDecorations; - TopLevelHost.UpdateDrawnDecorations(parts, EffectivePlatformWindowState); + TopLevelHost.UpdateDrawnDecorations(parts, WindowState); if (parts != null) { @@ -724,7 +689,7 @@ namespace Avalonia.Controls if (TopLevelHost.Decorations == null) return; - TopLevelHost.UpdateDrawnDecorations(ComputeDecorationParts(), EffectivePlatformWindowState); + TopLevelHost.UpdateDrawnDecorations(ComputeDecorationParts(), WindowState); } private Chrome.DrawnWindowDecorationParts? ComputeDecorationParts() @@ -748,7 +713,7 @@ namespace Avalonia.Controls // In fullscreen: no shadow, border, resize grips, or titlebar (popover takes over) - if (EffectivePlatformWindowState == WindowState.FullScreen) + if (WindowState == WindowState.FullScreen) { parts &= ~(Chrome.DrawnWindowDecorationParts.Shadow | Chrome.DrawnWindowDecorationParts.Border @@ -756,7 +721,7 @@ namespace Avalonia.Controls | Chrome.DrawnWindowDecorationParts.TitleBar); } // In maximized: no shadow, border, or resize grips (titlebar stays) - else if (EffectivePlatformWindowState == WindowState.Maximized) + else if (WindowState == WindowState.Maximized) { parts &= ~(Chrome.DrawnWindowDecorationParts.Shadow | Chrome.DrawnWindowDecorationParts.Border @@ -1245,7 +1210,7 @@ namespace Avalonia.Controls if (startupLocation == WindowStartupLocation.CenterOwner && (owner is null || - (owner is Window ownerWindow && ownerWindow.EffectivePlatformWindowState == WindowState.Minimized)) + (owner is Window ownerWindow && ownerWindow.WindowState == WindowState.Minimized)) ) { // If startup location is CenterOwner, but owner is null or minimized then fall back