diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/AlertsPage.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Core/AlertsPage.xaml.cs index 4e01e7daed1f..5e7fc768eaf8 100644 --- a/src/Controls/samples/Controls.Sample/Pages/Core/AlertsPage.xaml.cs +++ b/src/Controls/samples/Controls.Sample/Pages/Core/AlertsPage.xaml.cs @@ -11,6 +11,12 @@ public AlertsPage() InitializeComponent(); } + protected override async void OnAppearing() + { + base.OnAppearing(); + await DisplayAlert("Alert", "Welcome to the Alerts Page", "Hello!"); + } + async void OnAlertSimpleClicked(object sender, EventArgs e) { await DisplayAlert("Alert", "You have been alerted", "OK"); diff --git a/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Impl.cs b/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Impl.cs index 345cbb0dc2ac..2b38d3bf6b20 100644 --- a/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Impl.cs +++ b/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Impl.cs @@ -50,6 +50,7 @@ private protected override void OnHandlerChangedCore() base.OnHandlerChangedCore(); IsPlatformEnabled = Handler != null; + UpdatePlatformUnloadedLoadedWiring(Window); } Paint? IView.Background diff --git a/src/Controls/src/Core/Page.cs b/src/Controls/src/Core/Page.cs index a1c8f0f6ecf9..3584f6c39b1a 100644 --- a/src/Controls/src/Core/Page.cs +++ b/src/Controls/src/Core/Page.cs @@ -77,6 +77,7 @@ public Page() InternalChildren.CollectionChanged += InternalChildrenOnCollectionChanged; _platformConfigurationRegistry = new Lazy>(() => new PlatformConfigurationRegistry(this)); + this.NavigatedTo += FlushPendingActions; } /// @@ -251,16 +252,17 @@ public Task DisplayAlert(string title, string message, string accept, stri return args.Result.Task; } - internal override void OnIsPlatformEnabledChanged() + void FlushPendingActions(object sender, EventArgs e) { - base.OnIsPlatformEnabledChanged(); - if (IsPlatformEnabled && _pendingActions.Count > 0) + if (_pendingActions.Count > 0) { var actionsToProcess = _pendingActions.ToList(); _pendingActions.Clear(); foreach (var pendingAction in actionsToProcess) pendingAction(); } + + this.NavigatedTo -= FlushPendingActions; } /// diff --git a/src/Controls/src/Core/Platform/AlertManager/AlertManager.Windows.cs b/src/Controls/src/Core/Platform/AlertManager/AlertManager.Windows.cs index d64411f824e9..30f29e3b6b3d 100644 --- a/src/Controls/src/Core/Platform/AlertManager/AlertManager.Windows.cs +++ b/src/Controls/src/Core/Platform/AlertManager/AlertManager.Windows.cs @@ -182,11 +182,15 @@ void OnActionSheetRequested(Page sender, ActionSheetArguments arguments) if (pageParent != null) actionSheet.ShowAt(pageParent); + else + arguments.SetResult(null); } catch (ArgumentException) // If the page is not in the visual tree { - if (UI.Xaml.Window.Current.Content is FrameworkElement mainPage) + if (UI.Xaml.Window.Current != null && UI.Xaml.Window.Current.Content is FrameworkElement mainPage) actionSheet.ShowAt(mainPage); + else + arguments.SetResult(null); } } diff --git a/src/Controls/src/Core/Platform/AlertManager/AlertManager.iOS.cs b/src/Controls/src/Core/Platform/AlertManager/AlertManager.iOS.cs index d992f3f7d68b..69f91c709f3d 100644 --- a/src/Controls/src/Core/Platform/AlertManager/AlertManager.iOS.cs +++ b/src/Controls/src/Core/Platform/AlertManager/AlertManager.iOS.cs @@ -88,31 +88,27 @@ void OnActionSheetRequested(IView sender, ActionSheetArguments arguments) void PresentAlert(AlertArguments arguments) { - var window = new UIWindow { BackgroundColor = Colors.Transparent.ToPlatform() }; - var alert = UIAlertController.Create(arguments.Title, arguments.Message, UIAlertControllerStyle.Alert); var oldFrame = alert.View.Frame; alert.View.Frame = new RectF((float)oldFrame.X, (float)oldFrame.Y, (float)oldFrame.Width, (float)oldFrame.Height - AlertPadding * 2); if (arguments.Cancel != null) { - alert.AddAction(CreateActionWithWindowHide(arguments.Cancel, UIAlertActionStyle.Cancel, - () => arguments.SetResult(false), window)); + alert.AddAction(UIAlertAction.Create(arguments.Cancel, UIAlertActionStyle.Cancel, + _ => arguments.SetResult(false))); } if (arguments.Accept != null) { - alert.AddAction(CreateActionWithWindowHide(arguments.Accept, UIAlertActionStyle.Default, - () => arguments.SetResult(true), window)); + alert.AddAction(UIAlertAction.Create(arguments.Accept, UIAlertActionStyle.Default, + _ => arguments.SetResult(true))); } - PresentPopUp(window, alert); + PresentPopUp(Window, alert); } void PresentPrompt(PromptArguments arguments) { - var window = new UIWindow { BackgroundColor = Colors.Transparent.ToPlatform() }; - var alert = UIAlertController.Create(arguments.Title, arguments.Message, UIAlertControllerStyle.Alert); alert.AddTextField(uiTextField => { @@ -125,27 +121,26 @@ void PresentPrompt(PromptArguments arguments) var oldFrame = alert.View.Frame; alert.View.Frame = new RectF((float)oldFrame.X, (float)oldFrame.Y, (float)oldFrame.Width, (float)oldFrame.Height - AlertPadding * 2); - alert.AddAction(CreateActionWithWindowHide(arguments.Cancel, UIAlertActionStyle.Cancel, () => arguments.SetResult(null), window)); - alert.AddAction(CreateActionWithWindowHide(arguments.Accept, UIAlertActionStyle.Default, () => arguments.SetResult(alert.TextFields[0].Text), window)); + alert.AddAction(UIAlertAction.Create(arguments.Cancel, UIAlertActionStyle.Cancel, _ => arguments.SetResult(null))); + alert.AddAction(UIAlertAction.Create(arguments.Accept, UIAlertActionStyle.Default, _ => arguments.SetResult(alert.TextFields[0].Text))); - PresentPopUp(window, alert); + PresentPopUp(Window, alert); } void PresentActionSheet(ActionSheetArguments arguments) { var alert = UIAlertController.Create(arguments.Title, null, UIAlertControllerStyle.ActionSheet); - var window = new UIWindow { BackgroundColor = Colors.Transparent.ToPlatform() }; // Clicking outside of an ActionSheet is an implicit cancel on iPads. If we don't handle it, it freezes the app. if (arguments.Cancel != null || UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad) { - alert.AddAction(CreateActionWithWindowHide(arguments.Cancel ?? "", UIAlertActionStyle.Cancel, () => arguments.SetResult(arguments.Cancel), window)); + alert.AddAction(UIAlertAction.Create(arguments.Cancel ?? "", UIAlertActionStyle.Cancel, _ => arguments.SetResult(arguments.Cancel))); } if (arguments.Destruction != null) { - alert.AddAction(CreateActionWithWindowHide(arguments.Destruction, UIAlertActionStyle.Destructive, () => arguments.SetResult(arguments.Destruction), window)); + alert.AddAction(UIAlertAction.Create(arguments.Destruction, UIAlertActionStyle.Destructive, _ => arguments.SetResult(arguments.Destruction))); } foreach (var label in arguments.Buttons) @@ -155,18 +150,13 @@ void PresentActionSheet(ActionSheetArguments arguments) var blabel = label; - alert.AddAction(CreateActionWithWindowHide(blabel, UIAlertActionStyle.Default, () => arguments.SetResult(blabel), window)); + alert.AddAction(UIAlertAction.Create(blabel, UIAlertActionStyle.Default, _ => arguments.SetResult(blabel))); } - PresentPopUp(window, alert, arguments); + PresentPopUp(Window, alert, arguments); } static void PresentPopUp(UIWindow window, UIAlertController alert, ActionSheetArguments arguments = null) { - window.RootViewController = new UIViewController(); - window.RootViewController.View.BackgroundColor = Colors.Transparent.ToPlatform(); - window.WindowLevel = UIWindowLevel.Alert + 1; - window.MakeKeyAndVisible(); - if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad && arguments != null) { UIDevice.CurrentDevice.BeginGeneratingDeviceOrientationNotifications(); @@ -184,18 +174,11 @@ static void PresentPopUp(UIWindow window, UIAlertController alert, ActionSheetAr alert.PopoverPresentationController.PermittedArrowDirections = 0; // No arrow } - window.RootViewController.PresentViewController(alert, true, null); - } - - // Creates a UIAlertAction which includes a call to hide the presenting UIWindow at the end - UIAlertAction CreateActionWithWindowHide(string text, UIAlertActionStyle style, Action setResult, UIWindow window) - { - return UIAlertAction.Create(text, style, - action => - { - window.Hidden = true; - setResult(); - }); + window.BeginInvokeOnMainThread(() => + { + _ = window.RootViewController.PresentViewControllerAsync(alert, true); + }); + } } } diff --git a/src/Controls/tests/DeviceTests/Elements/VisualElementTests.cs b/src/Controls/tests/DeviceTests/Elements/VisualElementTests.cs index b965de089d29..5ec1827cf867 100644 --- a/src/Controls/tests/DeviceTests/Elements/VisualElementTests.cs +++ b/src/Controls/tests/DeviceTests/Elements/VisualElementTests.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.Maui.Controls; using Microsoft.Maui.Handlers; +using Microsoft.Maui.Hosting; using Xunit; namespace Microsoft.Maui.DeviceTests @@ -8,6 +9,22 @@ namespace Microsoft.Maui.DeviceTests [Category(TestCategory.VisualElement)] public partial class VisualElementTests : HandlerTestBase { + void SetupBuilder() + { + EnsureHandlerCreated(builder => + { + builder.ConfigureMauiHandlers(handlers => + { +#if WINDOWS || ANDROID + handlers.AddHandler(); + handlers.AddHandler(); +#else + handlers.AddHandler(); +#endif + }); + }); + } + [Fact] public async Task CanCreateHandler() { @@ -87,5 +104,35 @@ await CreateHandlerAndAddToWindow(parentLayout, async (handler) = Assert.Equal(2, loaded); Assert.Equal(2, unloaded); } + + [Fact] + public async Task LoadedFiresOnPushedPage() + { + SetupBuilder(); + + var navPage = new NavigationPage(new ContentPage()); + var page = new ContentPage(); + + int unloaded = 0; + int loaded = 0; + page.Loaded += (_, __) => loaded++; + page.Unloaded += (_, __) => unloaded++; + + await CreateHandlerAndAddToWindow(navPage, async (handler) => + { + Assert.Equal(0, loaded); + Assert.Equal(0, unloaded); + + await navPage.PushAsync(page); + + Assert.Equal(1, loaded); + Assert.Equal(0, unloaded); + + await navPage.PopAsync(); + + Assert.Equal(1, loaded); + Assert.Equal(1, unloaded); + }); + } } } \ No newline at end of file