diff --git a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt index 2defb52d4526..4e22034af3de 100644 --- a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt @@ -222,6 +222,7 @@ Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.SetResponse(int cod Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.Uri.get -> System.Uri! Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(Microsoft.Maui.Controls.PlatformWebViewWebResourceRequestedEventArgs! platformArgs) -> void Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(System.Uri! uri, string! method) -> void +Microsoft.Maui.Controls.Window.IsActivated.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.set -> void Microsoft.Maui.Controls.Window.IsMinimizable.get -> bool @@ -465,6 +466,7 @@ static readonly Microsoft.Maui.Controls.Border.SafeAreaEdgesProperty -> Microsof ~static readonly Microsoft.Maui.Controls.TemplatedView.IsClippedToBoundsProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TemplatedView.PaddingProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TimePicker.IsOpenProperty -> Microsoft.Maui.Controls.BindableProperty +static readonly Microsoft.Maui.Controls.Window.IsActivatedProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMaximizableProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMinimizableProperty -> Microsoft.Maui.Controls.BindableProperty! ~virtual Microsoft.Maui.Controls.BindableProperty.BindingPropertyChangedDelegate.Invoke(Microsoft.Maui.Controls.BindableObject bindable, object oldValue, object newValue) -> void diff --git a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt index 8bf7455b58fa..a765cb09c70d 100644 --- a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt @@ -207,6 +207,7 @@ Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.SetResponse(int cod Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.Uri.get -> System.Uri! Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(Microsoft.Maui.Controls.PlatformWebViewWebResourceRequestedEventArgs! platformArgs) -> void Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(System.Uri! uri, string! method) -> void +Microsoft.Maui.Controls.Window.IsActivated.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.set -> void Microsoft.Maui.Controls.Window.IsMinimizable.get -> bool @@ -453,6 +454,7 @@ static readonly Microsoft.Maui.Controls.Border.SafeAreaEdgesProperty -> Microsof ~static readonly Microsoft.Maui.Controls.TemplatedView.IsClippedToBoundsProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TemplatedView.PaddingProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TimePicker.IsOpenProperty -> Microsoft.Maui.Controls.BindableProperty +static readonly Microsoft.Maui.Controls.Window.IsActivatedProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMaximizableProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMinimizableProperty -> Microsoft.Maui.Controls.BindableProperty! ~virtual Microsoft.Maui.Controls.BindableProperty.BindingPropertyChangedDelegate.Invoke(Microsoft.Maui.Controls.BindableObject bindable, object oldValue, object newValue) -> void diff --git a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt index 8bf7455b58fa..a765cb09c70d 100644 --- a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt @@ -207,6 +207,7 @@ Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.SetResponse(int cod Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.Uri.get -> System.Uri! Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(Microsoft.Maui.Controls.PlatformWebViewWebResourceRequestedEventArgs! platformArgs) -> void Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(System.Uri! uri, string! method) -> void +Microsoft.Maui.Controls.Window.IsActivated.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.set -> void Microsoft.Maui.Controls.Window.IsMinimizable.get -> bool @@ -453,6 +454,7 @@ static readonly Microsoft.Maui.Controls.Border.SafeAreaEdgesProperty -> Microsof ~static readonly Microsoft.Maui.Controls.TemplatedView.IsClippedToBoundsProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TemplatedView.PaddingProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TimePicker.IsOpenProperty -> Microsoft.Maui.Controls.BindableProperty +static readonly Microsoft.Maui.Controls.Window.IsActivatedProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMaximizableProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMinimizableProperty -> Microsoft.Maui.Controls.BindableProperty! ~virtual Microsoft.Maui.Controls.BindableProperty.BindingPropertyChangedDelegate.Invoke(Microsoft.Maui.Controls.BindableObject bindable, object oldValue, object newValue) -> void diff --git a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt index 0fbfb8cf3540..fe8baa26b87d 100644 --- a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt @@ -216,6 +216,7 @@ Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.SetResponse(int cod Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.Uri.get -> System.Uri! Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(Microsoft.Maui.Controls.PlatformWebViewWebResourceRequestedEventArgs! platformArgs) -> void Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(System.Uri! uri, string! method) -> void +Microsoft.Maui.Controls.Window.IsActivated.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.set -> void Microsoft.Maui.Controls.Window.IsMinimizable.get -> bool @@ -456,6 +457,7 @@ static readonly Microsoft.Maui.Controls.Border.SafeAreaEdgesProperty -> Microsof ~static readonly Microsoft.Maui.Controls.TemplatedView.IsClippedToBoundsProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TemplatedView.PaddingProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TimePicker.IsOpenProperty -> Microsoft.Maui.Controls.BindableProperty +static readonly Microsoft.Maui.Controls.Window.IsActivatedProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMaximizableProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMinimizableProperty -> Microsoft.Maui.Controls.BindableProperty! ~virtual Microsoft.Maui.Controls.BindableProperty.BindingPropertyChangedDelegate.Invoke(Microsoft.Maui.Controls.BindableObject bindable, object oldValue, object newValue) -> void diff --git a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt index 112869fc21bf..c98a7b3105c1 100644 --- a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt @@ -199,6 +199,7 @@ Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.SetResponse(int cod Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.Uri.get -> System.Uri! Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(Microsoft.Maui.Controls.PlatformWebViewWebResourceRequestedEventArgs! platformArgs) -> void Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(System.Uri! uri, string! method) -> void +Microsoft.Maui.Controls.Window.IsActivated.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.set -> void Microsoft.Maui.Controls.Window.IsMinimizable.get -> bool @@ -435,6 +436,7 @@ static readonly Microsoft.Maui.Controls.Border.SafeAreaEdgesProperty -> Microsof ~static readonly Microsoft.Maui.Controls.TemplatedView.IsClippedToBoundsProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TemplatedView.PaddingProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TimePicker.IsOpenProperty -> Microsoft.Maui.Controls.BindableProperty +static readonly Microsoft.Maui.Controls.Window.IsActivatedProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMaximizableProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMinimizableProperty -> Microsoft.Maui.Controls.BindableProperty! ~virtual Microsoft.Maui.Controls.BindableProperty.BindingPropertyChangedDelegate.Invoke(Microsoft.Maui.Controls.BindableObject bindable, object oldValue, object newValue) -> void diff --git a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt index 112869fc21bf..c98a7b3105c1 100644 --- a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt @@ -199,6 +199,7 @@ Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.SetResponse(int cod Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.Uri.get -> System.Uri! Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(Microsoft.Maui.Controls.PlatformWebViewWebResourceRequestedEventArgs! platformArgs) -> void Microsoft.Maui.Controls.WebViewWebResourceRequestedEventArgs.WebViewWebResourceRequestedEventArgs(System.Uri! uri, string! method) -> void +Microsoft.Maui.Controls.Window.IsActivated.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.get -> bool Microsoft.Maui.Controls.Window.IsMaximizable.set -> void Microsoft.Maui.Controls.Window.IsMinimizable.get -> bool @@ -435,6 +436,7 @@ static readonly Microsoft.Maui.Controls.Border.SafeAreaEdgesProperty -> Microsof ~static readonly Microsoft.Maui.Controls.TemplatedView.IsClippedToBoundsProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TemplatedView.PaddingProperty -> Microsoft.Maui.Controls.BindableProperty ~static readonly Microsoft.Maui.Controls.TimePicker.IsOpenProperty -> Microsoft.Maui.Controls.BindableProperty +static readonly Microsoft.Maui.Controls.Window.IsActivatedProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMaximizableProperty -> Microsoft.Maui.Controls.BindableProperty! static readonly Microsoft.Maui.Controls.Window.IsMinimizableProperty -> Microsoft.Maui.Controls.BindableProperty! ~virtual Microsoft.Maui.Controls.BindableProperty.BindingPropertyChangedDelegate.Invoke(Microsoft.Maui.Controls.BindableObject bindable, object oldValue, object newValue) -> void diff --git a/src/Controls/src/Core/Window/Window.cs b/src/Controls/src/Core/Window/Window.cs index af82bb140fc9..b4a744343101 100644 --- a/src/Controls/src/Core/Window/Window.cs +++ b/src/Controls/src/Core/Window/Window.cs @@ -14,6 +14,12 @@ namespace Microsoft.Maui.Controls [ContentProperty(nameof(Page))] public partial class Window : NavigableElement, IWindow, IToolbarElement, IMenuBarElement, IFlowDirectionController, IWindowController { + static readonly BindablePropertyKey IsActivatedPropertyKey = + BindableProperty.CreateReadOnly(nameof(IsActivated), typeof(bool), typeof(Window), false, propertyChanged: OnIsActivatedPropertyChanged); + + /// Bindable property for . + public static readonly BindableProperty IsActivatedProperty = IsActivatedPropertyKey.BindableProperty; + /// Bindable property for . public static readonly BindableProperty TitleProperty = BindableProperty.Create( nameof(Title), typeof(string), typeof(Window), default(string?)); @@ -76,7 +82,6 @@ public partial class Window : NavigableElement, IWindow, IToolbarElement, IMenuB List _visualChildren; Toolbar? _toolbar; MenuBarTracker _menuBarTracker; - bool _isActivated; IToolbar? IToolbarElement.Toolbar => Toolbar; internal Toolbar? Toolbar @@ -117,6 +122,12 @@ public string? Title set => SetValue(TitleProperty, value); } + public bool IsActivated + { + get => (bool)GetValue(IsActivatedProperty); + private set => SetValue(IsActivatedPropertyKey, value); + } + string? ITitledElement.Title => Title ?? (Page as Shell)?.Title; public Page? Page @@ -324,24 +335,6 @@ public bool RemoveOverlay(IWindowOverlay overlay) internal IMauiContext MauiContext => Handler?.MauiContext ?? throw new InvalidOperationException("MauiContext is null."); - internal bool IsActivated - { - get - { - return _isActivated; - } - private set - { - if (_isActivated == value) - return; - - _isActivated = value; - - if (value) - SendWindowAppearing(); - } - } - internal bool IsDestroyed { get; private set; } internal bool IsCreated { get; private set; } @@ -634,6 +627,15 @@ static void OnPageChanging(BindableObject bindable, object oldValue, object newV oldPage.SendDisappearing(); } + static void OnIsActivatedPropertyChanged(BindableObject bindable, object oldValue, object newValue) + { + var window = (Window)bindable; + if ((bool)newValue) + { + window.SendWindowAppearing(); + } + } + void OnPageChanged(Page? oldPage, Page? newPage) { if (oldPage != null) diff --git a/src/Controls/tests/Core.UnitTests/WindowsTests.cs b/src/Controls/tests/Core.UnitTests/WindowsTests.cs index 3f9599e00ec4..d63f48204ea4 100644 --- a/src/Controls/tests/Core.UnitTests/WindowsTests.cs +++ b/src/Controls/tests/Core.UnitTests/WindowsTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading; using System.Threading.Tasks; using Microsoft.Maui.Graphics; using Xunit; @@ -649,6 +650,74 @@ public void PreviousShellDisconnectsFromWindowPropertyChanged() Assert.False(fired); } + [Fact] + public void CreateWindowKeepIsActivatedIsFalse() + { + var app = new TestApp(); + + var window = app.CreateWindow(); + + Assert.False(window.IsActivated); + } + + [Fact] + public void ActivateWindowWillSetIsActiveToTrue() + { + var app = new TestApp(); + + var window = app.CreateWindow(); + + (window as IWindow).Activated(); + + Assert.True(window.IsActivated); + } + + [Fact] + public void ActivateWindowAndDeactivateWillSetIsActiveToFalse() + { + var app = new TestApp(); + + var window = app.CreateWindow(); + + (window as IWindow).Activated(); + + Assert.True(window.IsActivated); + + (window as IWindow).Deactivated(); + + Assert.False(window.IsActivated); + } + + [Fact] + public async Task ActivateWindowSendAppearingOnPage() + { + var app = new TestApp(); + + var window = app.CreateWindow(); + + var page = new ContentPage(); + + window.Page = page; + + page.SendDisappearing(); + + var tcs = new TaskCompletionSource(); + + using var cts = new CancellationTokenSource(); + using var _ = cts.Token.Register(() => tcs.SetResult(false)); + + page.Appearing += (_, __) => + { + tcs.SetResult(true); + }; + + cts.CancelAfter(TimeSpan.FromSeconds(5)); + + (window as IWindow).Activated(); + + Assert.True(await tcs.Task); + } + [Theory] [InlineData(double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN)] [InlineData(-1, -1, -1, -1, -1, -1, double.NaN, double.NaN)] @@ -766,5 +835,34 @@ public async Task TwoKeysSameWindow() Assert.Same(window, actual); Assert.Empty(table); } + + [Fact] + public void BindingIsActivatedProperty() + { + var app = new TestApp(); + var page = new ContentPage(); + var window = app.CreateWindow(); + window.Page = page; + + var vm = new ViewModel(); + window.BindingContext = vm; + window.SetBinding(Window.IsActivatedProperty, nameof(vm.IsWindowActive)); + + (window as IWindow).Activated(); + + Assert.True(vm.IsWindowActive); + + (window as IWindow).Deactivated(); + + Assert.False(vm.IsWindowActive); + } + } + + class ViewModel + { + public bool IsWindowActive + { + get; set; + } } } diff --git a/src/Controls/tests/DeviceTests/Elements/Window/WindowTests.cs b/src/Controls/tests/DeviceTests/Elements/Window/WindowTests.cs index fca282fbbe4e..dbe5533fe0e1 100644 --- a/src/Controls/tests/DeviceTests/Elements/Window/WindowTests.cs +++ b/src/Controls/tests/DeviceTests/Elements/Window/WindowTests.cs @@ -232,5 +232,57 @@ await firstPage.Handler.MauiContext.Services.GetRequiredService() Assert.True(passed); } + + [Fact] + public async Task WindowIsActivedRespondToMethodsCall() + { + SetupBuilder(); + var page = new ContentPage(); + var window = new Window(page); + + await CreateHandlerAndAddToWindow(window, (h) => + { + var w = h.VirtualView; + + Assert.True(window.IsActivated); + + w.Deactivated(); + + Assert.False(window.IsActivated); + }); + } + + [Fact] + public async Task SwitchBetweenWindowShouldTriggerIsActivated() + { + SetupBuilder(); + var page = new ContentPage(); + var app = ApplicationServices.GetService() as ApplicationStub; + + var window1 = new Window(page); + var window2 = new Window(page); + + await CreateHandlerAndAddToWindow(window1, (h) => + { + app.OpenWindow(window1); + Assert.True(window1.IsActivated); + Assert.False(window2.IsActivated); + }); + + + await CreateHandlerAndAddToWindow(window2, (h) => + { + app.OpenWindow(window2); + + Assert.False(window1.IsActivated); + Assert.True(window2.IsActivated); + }); + + app.CloseWindow(window2); + app.CloseWindow(window1); + + Assert.False(window1.IsActivated); + Assert.False(window2.IsActivated); + } } }