diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue20612.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue20612.cs new file mode 100644 index 000000000000..a513d8aaf0b8 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue20612.cs @@ -0,0 +1,94 @@ +using Microsoft.Maui.Maps; + +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 20612, "Disconnecting Map Handler causes Map to crash on second page entrance and moving to region.", PlatformAffected.iOS | PlatformAffected.macOS)] +public class Issue20612 : TestNavigationPage +{ + protected override void Init() + { + PushAsync(new Issue20612page1()); + } +} + +public class Issue20612page1 : ContentPage +{ + public Issue20612page1() + { + var openMapButton = new Button + { + Text = "Navigate to Map page", + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + AutomationId = "MapButton" + }; + + openMapButton.Clicked += (s, e) => + { + Navigation.PushAsync(new Issue20612page2()); + }; + Content = openMapButton; + } +} + +public class Issue20612page2 : ContentPage +{ + private Microsoft.Maui.Controls.Maps.Map _map; + + public Issue20612page2() + { + _map = new Microsoft.Maui.Controls.Maps.Map + { + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill, + BackgroundColor = Colors.Red + }; + + var goBackButton = new Button + { + Text = "Go back", + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + AutomationId = "GoBackButton" + }; + goBackButton.Clicked += GoBack; + + var grid = new Grid + { + RowDefinitions = + { + new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }, // Row 0: for map + new RowDefinition { Height = GridLength.Auto } // Row 1: for button + } + }; + + grid.Children.Add(_map); + Grid.SetRow(_map, 0); + + grid.Children.Add(goBackButton); + Grid.SetRow(goBackButton, 1); + Content = grid; + + MoveMap(); + } + + private async void MoveMap() + { + await Task.Delay(1000).ConfigureAwait(false); + + MainThread.BeginInvokeOnMainThread(() => + { + var mapSpan = MapSpan.FromCenterAndRadius( + new Location(5, 5), + Distance.FromMeters(10000)); + + _map.MoveToRegion(mapSpan); + }); + } + + void GoBack(object sender, EventArgs e) + { + _map.Handler?.DisconnectHandler(); + Navigation.PopAsync(); + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue20612.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue20612.cs new file mode 100644 index 000000000000..edc96e423c10 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue20612.cs @@ -0,0 +1,27 @@ +#if TEST_FAILS_ON_WINDOWS +//No Map control support in windows https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/map?view=net-maui-9.0 +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; +public class Issue20612 : _IssuesUITest +{ + public Issue20612(TestDevice device) : base(device) { } + + public override string Issue => "Disconnecting Map Handler causes Map to crash on second page entrance and moving to region."; + + [Test] + [Category(UITestCategories.Maps)] + public void MapsShouldNotCrashWhenNavigationOccurs() + { + App.WaitForElement("MapButton"); + App.Tap("MapButton"); + App.WaitForElement("GoBackButton"); + App.Tap("GoBackButton"); + // second Navigation to Map page + App.WaitForElement("MapButton"); + App.Tap("MapButton"); + } +} +#endif \ No newline at end of file diff --git a/src/Core/maps/src/Handlers/Map/MapHandler.iOS.cs b/src/Core/maps/src/Handlers/Map/MapHandler.iOS.cs index 7fa40cfc68b0..181105ff4f0c 100644 --- a/src/Core/maps/src/Handlers/Map/MapHandler.iOS.cs +++ b/src/Core/maps/src/Handlers/Map/MapHandler.iOS.cs @@ -13,7 +13,7 @@ public partial class MapHandler : ViewHandler protected override MauiMKMapView CreatePlatformView() { - return MapPool.Get() ?? new MauiMKMapView(this); + return MapPool.Get(this) ?? new MauiMKMapView(this); } protected override void ConnectHandler(MauiMKMapView platformView) diff --git a/src/Core/maps/src/Platform/iOS/MapPool.cs b/src/Core/maps/src/Platform/iOS/MapPool.cs index 801229429a1b..dd2fe8258f88 100644 --- a/src/Core/maps/src/Platform/iOS/MapPool.cs +++ b/src/Core/maps/src/Platform/iOS/MapPool.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using Microsoft.Maui.Maps.Handlers; namespace Microsoft.Maui.Maps.Platform { @@ -11,6 +12,14 @@ internal class MapPool public static void Add(MauiMKMapView mapView) => Instance.Maps.Enqueue(mapView); - public static MauiMKMapView? Get() => Instance.Maps.TryDequeue(out MauiMKMapView? mapView) ? mapView : null; + public static MauiMKMapView? Get(IMapHandler mapHandler) + { + if (Instance.Maps.TryDequeue(out MauiMKMapView? mapView) && mapView is not null) + { + mapView.Handler = mapHandler; + return mapView; + } + return null; + } } } diff --git a/src/Core/maps/src/Platform/iOS/MauiMKMapView.cs b/src/Core/maps/src/Platform/iOS/MauiMKMapView.cs index 2f5be1447c52..e52025abeb5b 100644 --- a/src/Core/maps/src/Platform/iOS/MauiMKMapView.cs +++ b/src/Core/maps/src/Platform/iOS/MauiMKMapView.cs @@ -22,6 +22,22 @@ public MauiMKMapView(IMapHandler handler) OverlayRenderer = GetViewForOverlayDelegate; } + internal IMapHandler? Handler + { + get + { + _handlerRef.TryGetTarget(out var handler); + return handler; + } + set + { + if (value is not null) + { + _handlerRef = new WeakReference(value); + } + } + } + public override void MovedToWindow() { base.MovedToWindow();