diff --git a/Mopups/Mopups.Maui/Mopups.csproj b/Mopups/Mopups.Maui/Mopups.csproj index 7aff78f..a4deadd 100644 --- a/Mopups/Mopups.Maui/Mopups.csproj +++ b/Mopups/Mopups.Maui/Mopups.csproj @@ -110,6 +110,6 @@ - + diff --git a/Mopups/Mopups.Maui/Platforms/Android/Impl/AndroidMopups.cs b/Mopups/Mopups.Maui/Platforms/Android/Impl/AndroidMopups.cs index c3a6392..5057a3a 100644 --- a/Mopups/Mopups.Maui/Platforms/Android/Impl/AndroidMopups.cs +++ b/Mopups/Mopups.Maui/Platforms/Android/Impl/AndroidMopups.cs @@ -44,7 +44,7 @@ public class AndroidMopups : IPopupPlatform return AddAsync(page, null); } - public Task AddAsync(PopupPage page, Window? targetWindow) + public Task AddAsync(PopupPage page, Microsoft.Maui.Controls.Window? targetWindow) { HandleAccessibility(true, page.DisableAndroidAccessibilityHandling, page); diff --git a/Mopups/Mopups.Maui/Platforms/MacCatalyst/Handler/PopupPageRenderer.cs b/Mopups/Mopups.Maui/Platforms/MacCatalyst/Handler/PopupPageRenderer.cs index 8d75ae7..6c7abb8 100644 --- a/Mopups/Mopups.Maui/Platforms/MacCatalyst/Handler/PopupPageRenderer.cs +++ b/Mopups/Mopups.Maui/Platforms/MacCatalyst/Handler/PopupPageRenderer.cs @@ -59,7 +59,11 @@ namespace Mopups.Platforms.MacCatalyst if (Equals(subview, view)) { - ((PopupPage)Handler.VirtualView).SendBackgroundClick(); + try + { + (Handler.VirtualView as PopupPage)?.SendBackgroundClick(); + } + catch (InvalidOperationException) { } } } @@ -74,30 +78,36 @@ namespace Mopups.Platforms.MacCatalyst void UpdateSize(PopupPageRenderer handler) { - var currentElement = ((PopupPage)Handler.VirtualView); - - if (handler.Handler.PlatformView?.Superview?.Frame == null || currentElement == null) - return; - - var superviewFrame = handler.Handler.PlatformView.Superview.Frame; - var applicationFrame = UIScreen.MainScreen.ApplicationFrame; - - var systemPadding = new Thickness + try { - Left = applicationFrame.Left, - Top = applicationFrame.Top, - Right = applicationFrame.Right - applicationFrame.Width - applicationFrame.Left, - Bottom = applicationFrame.Bottom - applicationFrame.Height - applicationFrame.Top + handler.KeyboardBounds.Height - }; + var currentElement = Handler.VirtualView as PopupPage; - if ((handler.Handler.VirtualView.Width != superviewFrame.Width && handler.Handler.VirtualView.Height != superviewFrame.Height) - || currentElement.SystemPadding.Bottom != systemPadding.Bottom) - { - currentElement.BatchBegin(); - currentElement.SystemPadding = systemPadding; - currentElement.Layout(new Rect(currentElement.X, currentElement.Y, superviewFrame.Width, superviewFrame.Height)); - currentElement.BatchCommit(); + if (handler.Handler.PlatformView?.Superview?.Frame == null || currentElement == null) + return; + + var superviewFrame = handler.Handler.PlatformView.Superview.Frame; + var applicationFrame = UIScreen.MainScreen.ApplicationFrame; + + var systemPadding = new Thickness + { + Left = applicationFrame.Left, + Top = applicationFrame.Top, + Right = applicationFrame.Right - applicationFrame.Width - applicationFrame.Left, + Bottom = applicationFrame.Bottom - applicationFrame.Height - applicationFrame.Top + handler.KeyboardBounds.Height + }; + + var virtualView = handler.Handler.VirtualView; + if (virtualView != null && + ((virtualView.Width != superviewFrame.Width && virtualView.Height != superviewFrame.Height) + || currentElement.SystemPadding.Bottom != systemPadding.Bottom)) + { + currentElement.BatchBegin(); + currentElement.SystemPadding = systemPadding; + currentElement.Layout(new Rect(currentElement.X, currentElement.Y, superviewFrame.Width, superviewFrame.Height)); + currentElement.BatchCommit(); + } } + catch (InvalidOperationException) { } } } diff --git a/Mopups/Mopups.Maui/Platforms/Windows/Handler/PopupPageHandler.cs b/Mopups/Mopups.Maui/Platforms/Windows/Handler/PopupPageHandler.cs index 08d994c..15b0988 100644 --- a/Mopups/Mopups.Maui/Platforms/Windows/Handler/PopupPageHandler.cs +++ b/Mopups/Mopups.Maui/Platforms/Windows/Handler/PopupPageHandler.cs @@ -6,6 +6,8 @@ namespace Mopups.Platforms.Windows { public class PopupPageHandler : PageHandler { + private Microsoft.UI.Xaml.SizeChangedEventHandler? _sizeChangedHandler; + public PopupPageHandler() { } @@ -14,7 +16,25 @@ namespace Mopups.Platforms.Windows { base.ConnectHandler(platformView); - PlatformView.SizeChanged += (_, e) => VirtualView.ComputeDesiredSize(e.NewSize.Width, e.NewSize.Height); + _sizeChangedHandler = (_, e) => + { + try + { + VirtualView?.ComputeDesiredSize(e.NewSize.Width, e.NewSize.Height); + } + catch (InvalidOperationException) { } + }; + PlatformView.SizeChanged += _sizeChangedHandler; + } + + protected override void DisconnectHandler(ContentPanel platformView) + { + if (_sizeChangedHandler != null) + { + platformView.SizeChanged -= _sizeChangedHandler; + _sizeChangedHandler = null; + } + base.DisconnectHandler(platformView); } protected override ContentPanel CreatePlatformView() diff --git a/Mopups/Mopups.Maui/Platforms/Windows/Handler/PopupPageRenderer.cs b/Mopups/Mopups.Maui/Platforms/Windows/Handler/PopupPageRenderer.cs index 49d366f..6c069aa 100644 --- a/Mopups/Mopups.Maui/Platforms/Windows/Handler/PopupPageRenderer.cs +++ b/Mopups/Mopups.Maui/Platforms/Windows/Handler/PopupPageRenderer.cs @@ -15,7 +15,20 @@ namespace Mopups.Platforms.Windows internal WinPopup? Container { get; private set; } - private PopupPage CurrentElement => (PopupPage)handler.VirtualView; + private PopupPage? CurrentElement + { + get + { + try + { + return handler.VirtualView as PopupPage; + } + catch (InvalidOperationException) + { + return null; + } + } + } public PopupPageRenderer(PopupPageHandler handler) { @@ -92,7 +105,7 @@ namespace Mopups.Platforms.Windows { if ((e.OriginalSource as PopupPageRenderer) == this) { - CurrentElement.SendBackgroundClick(); + CurrentElement?.SendBackgroundClick(); } } diff --git a/Mopups/Mopups.Maui/Platforms/Windows/Impl/PopupPlatformWindows.cs b/Mopups/Mopups.Maui/Platforms/Windows/Impl/PopupPlatformWindows.cs index 2eb5afc..6a3222d 100644 --- a/Mopups/Mopups.Maui/Platforms/Windows/Impl/PopupPlatformWindows.cs +++ b/Mopups/Mopups.Maui/Platforms/Windows/Impl/PopupPlatformWindows.cs @@ -56,34 +56,33 @@ namespace Mopups.Windows.Implementation public async Task AddAsync(PopupPage page, Window? window) { - var mainPage = Application.Current.MainPage; - mainPage.AddLogicalChild(page); - - var popup = new global::Microsoft.UI.Xaml.Controls.Primitives.Popup(); - - // Use TOPLATFORM to create your handlers - // I'd recommend wiring up all your services through ConfigureMopups - // builder.Services.AddScoped(); - // builder.Services.AddScoped(); - // Then you can use contructor resolution instead of singletons - // But I figured we could do that in a later PR and just work on windows here - - var renderer = (PopupPageRenderer)page.ToPlatform(mainPage.Handler.MauiContext); - renderer.Prepare(popup); - popup.Child = renderer; - - // https://github.com/microsoft/microsoft-ui-xaml/issues/3389 - // Use the specified window's XamlRoot if provided, otherwise fall back to main window + // Use target window's page if provided, otherwise fall back to MainPage + Page parentPage; + IMauiContext mauiContext; Microsoft.UI.Xaml.Window nativeWindow; - if (window?.Handler?.PlatformView is Microsoft.UI.Xaml.Window targetWindow) + + if (window?.Handler?.PlatformView is Microsoft.UI.Xaml.Window targetWindow && window.Page != null) { + parentPage = window.Page; + mauiContext = window.Handler.MauiContext!; nativeWindow = targetWindow; } else { - nativeWindow = mainPage.Handler.MauiContext.Services.GetService(); + parentPage = Application.Current.MainPage; + mauiContext = parentPage.Handler.MauiContext; + nativeWindow = mauiContext.Services.GetService(); } + parentPage.AddLogicalChild(page); + + var popup = new global::Microsoft.UI.Xaml.Controls.Primitives.Popup(); + + var renderer = (PopupPageRenderer)page.ToPlatform(mauiContext); + renderer.Prepare(popup); + popup.Child = renderer; + + // https://github.com/microsoft/microsoft-ui-xaml/issues/3389 popup.XamlRoot = nativeWindow.Content.XamlRoot; popup.IsOpen = true; page.ForceLayout(); @@ -96,17 +95,35 @@ namespace Mopups.Windows.Implementation if (page == null) throw new Exception("Popup page is null"); - var renderer = (PopupPageRenderer)page.ToPlatform(Application.Current.MainPage.Handler.MauiContext); - var popup = renderer.Container; + // Get the handler before we start cleanup + var handler = page.Handler; + if (handler == null) + { + // Already cleaned up + page.Parent?.RemoveLogicalChild(page); + return; + } + + var renderer = handler.PlatformView as PopupPageRenderer; + var popup = renderer?.Container; if (popup != null) { - renderer.Destroy(); - - Cleanup(page); - page.Parent?.RemoveLogicalChild(page); - popup.Child = null; + // First close the popup to stop layout events popup.IsOpen = false; + popup.Child = null; + + // Now safe to destroy and cleanup + renderer?.Destroy(); + page.Parent?.RemoveLogicalChild(page); + + // Disconnect handler last + Cleanup(page); + } + else + { + page.Parent?.RemoveLogicalChild(page); + Cleanup(page); } await Task.Delay(5); diff --git a/Mopups/Mopups.Maui/Platforms/iOS/Handler/PopupPageRenderer.cs b/Mopups/Mopups.Maui/Platforms/iOS/Handler/PopupPageRenderer.cs index d47a8b3..1c5c963 100644 --- a/Mopups/Mopups.Maui/Platforms/iOS/Handler/PopupPageRenderer.cs +++ b/Mopups/Mopups.Maui/Platforms/iOS/Handler/PopupPageRenderer.cs @@ -59,7 +59,11 @@ namespace Mopups.Platforms.iOS if (Equals(subview, view)) { - ((PopupPage)Handler.VirtualView).SendBackgroundClick(); + try + { + (Handler.VirtualView as PopupPage)?.SendBackgroundClick(); + } + catch (InvalidOperationException) { } } } @@ -74,30 +78,36 @@ namespace Mopups.Platforms.iOS void UpdateSize(PopupPageRenderer handler) { - var currentElement = ((PopupPage)Handler.VirtualView); - - if (handler.Handler.PlatformView?.Superview?.Frame == null || currentElement == null) - return; - - var superviewFrame = handler.Handler.PlatformView.Superview.Frame; - var applicationFrame = UIScreen.MainScreen.ApplicationFrame; - - var systemPadding = new Thickness + try { - Left = applicationFrame.Left, - Top = applicationFrame.Top, - Right = applicationFrame.Right - applicationFrame.Width - applicationFrame.Left, - Bottom = applicationFrame.Bottom - applicationFrame.Height - applicationFrame.Top + handler.KeyboardBounds.Height - }; + var currentElement = Handler.VirtualView as PopupPage; - if ((handler.Handler.VirtualView.Width != superviewFrame.Width && handler.Handler.VirtualView.Height != superviewFrame.Height) - || currentElement.SystemPadding.Bottom != systemPadding.Bottom) - { - currentElement.BatchBegin(); - currentElement.SystemPadding = systemPadding; - currentElement.Layout(new Rect(currentElement.X, currentElement.Y, superviewFrame.Width, superviewFrame.Height)); - currentElement.BatchCommit(); + if (handler.Handler.PlatformView?.Superview?.Frame == null || currentElement == null) + return; + + var superviewFrame = handler.Handler.PlatformView.Superview.Frame; + var applicationFrame = UIScreen.MainScreen.ApplicationFrame; + + var systemPadding = new Thickness + { + Left = applicationFrame.Left, + Top = applicationFrame.Top, + Right = applicationFrame.Right - applicationFrame.Width - applicationFrame.Left, + Bottom = applicationFrame.Bottom - applicationFrame.Height - applicationFrame.Top + handler.KeyboardBounds.Height + }; + + var virtualView = handler.Handler.VirtualView; + if (virtualView != null && + ((virtualView.Width != superviewFrame.Width && virtualView.Height != superviewFrame.Height) + || currentElement.SystemPadding.Bottom != systemPadding.Bottom)) + { + currentElement.BatchBegin(); + currentElement.SystemPadding = systemPadding; + currentElement.Layout(new Rect(currentElement.X, currentElement.Y, superviewFrame.Width, superviewFrame.Height)); + currentElement.BatchCommit(); + } } + catch (InvalidOperationException) { } } }