diff --git a/src/Controls/samples/Controls.Sample.UITests/Issues/Issue17347.cs b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue17347.cs new file mode 100644 index 000000000000..fbf889f4e779 --- /dev/null +++ b/src/Controls/samples/Controls.Sample.UITests/Issues/Issue17347.cs @@ -0,0 +1,65 @@ +using System; +using Microsoft.Maui.Controls; + +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.Github, 17347, "Setting a new TitleView on an already created page crashes iOS", PlatformAffected.iOS)] + public class Issue17347 : TestContentPage + { + protected override void Init() + { + var navPage = new NavigationPage(new MainPage()); + NavigatedTo += Issue16499_NavigatedTo; + + async void Issue16499_NavigatedTo(object sender, NavigatedToEventArgs e) + { + NavigatedTo -= Issue16499_NavigatedTo; + + await Navigation.PushModalAsync(navPage); + await navPage.Navigation.PushAsync(new MainPage()); + await navPage.Navigation.PushAsync(new MainPage()); + await navPage.Navigation.PopAsync(); + await navPage.Navigation.PopAsync(); + } + } + + public partial class MainPage : ContentPage + { + Label TopView; + static int i = 0; + protected override void OnAppearing() + { + Content = new VerticalStackLayout() + { + new Button() + { + AutomationId = "PopMeButton", + Command = new Command(async () => + { + if (Navigation.NavigationStack.Count == 1) + await Navigation.PopModalAsync(); + else + await Navigation.PopAsync(); + }), + Text = "Click to Pop This Page If Needed" + } + }; + + var increment = $"{i++}"; + TopView = new() + { + AutomationId = "TitleViewLabel" + increment + }; + + TopView.SetBinding(Label.TextProperty, "AutomationId"); + TopView.BindingContext = TopView; + + TopView.WidthRequest = App.Current.Windows[0].Page.Width / 2; + NavigationPage.SetTitleView(this, TopView); + NavigationPage.SetHasNavigationBar(this, true); + NavigationPage.SetHasBackButton(this, false); + base.OnAppearing(); + } + } + } +} diff --git a/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs index 9b2764c67d45..80871ac000e5 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs @@ -1759,14 +1759,40 @@ public Container(View view, UINavigationBar bar) : base(bar.Bounds) if (view != null) { _view = view; - var platformView = view.ToPlatform(view.FindMauiContext()); - _child = (IPlatformViewHandler)view.Handler; - AddSubview(platformView); + + if (_view.Parent is null) + { + _view.ParentSet += OnTitleViewParentSet; + } + else + { + SetupTitleView(); + } } ClipsToBounds = true; } + void OnTitleViewParentSet(object sender, EventArgs e) + { + if (sender is View view) + view.ParentSet -= OnTitleViewParentSet; + + SetupTitleView(); + } + + void SetupTitleView() + { + var mauiContext = _view.FindMauiContext(); + if (_view is not null && mauiContext is not null) + { + var platformView = _view.ToPlatform(mauiContext); + _child = (IPlatformViewHandler)_view.Handler; + AddSubview(platformView); + } + + } + public override CGSize IntrinsicContentSize => UILayoutFittingExpandedSize; nfloat IconHeight => _icon?.Frame.Height ?? 0; @@ -1874,6 +1900,11 @@ protected override void Dispose(bool disposing) _child = null; } + if (_view is not null) + { + _view.ParentSet -= OnTitleViewParentSet; + } + _view = null; _icon?.Dispose(); diff --git a/src/Controls/tests/UITests/Tests/Issues/Issue17347.cs b/src/Controls/tests/UITests/Tests/Issues/Issue17347.cs new file mode 100644 index 000000000000..a1182cd546d6 --- /dev/null +++ b/src/Controls/tests/UITests/Tests/Issues/Issue17347.cs @@ -0,0 +1,29 @@ +using System.Drawing; +using Microsoft.Maui.Appium; +using NUnit.Framework; +using OpenQA.Selenium.Appium.MultiTouch; +using TestUtils.Appium.UITests; + +namespace Microsoft.Maui.AppiumTests.Issues +{ + public class Issue17347 : _IssuesUITest + { + public Issue17347(TestDevice device) : base(device) + { + } + + public override string Issue => "Setting a new TitleView on an already created page crashes iOS"; + + [Test] + public void AppDoesntCrashWhenSettingNewTitleViewOnExistingPage() { + try + { + App.WaitForElement("TitleViewLabel4", timeout: TimeSpan.FromSeconds(4)); + } + finally + { + App.Tap("PopMeButton"); + } + } + } +}