Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/Controls/src/Core/Page/Page.cs
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,7 @@ internal Toolbar Toolbar

internal void SendNavigatedTo(NavigatedToEventArgs args)
{
// Prevent duplicate OnNavigatedTo during a single navigation burst (fixes #23902).
if (HasNavigatedTo)
{
return;
Expand All @@ -848,7 +849,21 @@ internal void SendNavigatedTo(NavigatedToEventArgs args)
HasNavigatedTo = true;
NavigatedTo?.Invoke(this, args);
OnNavigatedTo(args);
(this as IPageContainer<Page>)?.CurrentPage?.SendNavigatedTo(args);

// Cascade to child page (e.g. TabbedPage → CurrentPage).
// On Pop, reset the child flag first — a prior tab change while a modal was open
// can leave it true, which would incorrectly block the pop-return (fixes #35756).
// PopToRoot is excluded: SendNavigatedFrom already resets all flags before PopToRoot cascades.
var containerChild = (this as IPageContainer<Page>)?.CurrentPage;
if (containerChild is not null)
{
if (args.NavigationType == NavigationType.Pop)
{
containerChild.HasNavigatedTo = false;
}

containerChild.SendNavigatedTo(args);
}
}

internal void SendNavigatingFrom(NavigatingFromEventArgs args)
Expand Down
126 changes: 126 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue35756.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
using Microsoft.Maui.Controls;

namespace Maui.Controls.Sample.Issues
{
[Issue(IssueTracker.Github, 35756, "OnNavigatedTo does not fire after PopModalAsync when tab was changed from inside the modal", PlatformAffected.All)]
public class Issue35756TabbedPage : TabbedPage
{
public Issue35756TabbedPage()
{
Title = "Issue35756";
Children.Add(new Issue35756Tab1Page());
Children.Add(new Issue35756Tab2Page(this));
}
}

public class Issue35756Tab1Page : ContentPage
{
readonly Label _navigatedToCountLabel;
int _navigatedToCount;

public Issue35756Tab1Page()
{
Title = "Tab 1";
_navigatedToCountLabel = new Label
{
AutomationId = "Tab1NavigatedToCount",
Text = "NavigatedTo count: 0"
};
Content = new StackLayout
{
Padding = 20,
Children =
{
new Label { Text = "Tab 1", FontSize = 18, AutomationId = "Tab1Content" },
_navigatedToCountLabel
}
};
}

protected override void OnNavigatedTo(NavigatedToEventArgs args)
{
base.OnNavigatedTo(args);
_navigatedToCount++;
_navigatedToCountLabel.Text = $"NavigatedTo count: {_navigatedToCount}";
}
}

public class Issue35756Tab2Page : ContentPage
{
readonly TabbedPage _tabbedPage;

public Issue35756Tab2Page(TabbedPage tabbedPage)
{
Title = "Tab 2";
_tabbedPage = tabbedPage;

var pushModalButton = new Button
{
Text = "Push Modal",
AutomationId = "PushModalButton"
};
pushModalButton.Clicked += OnPushModalClicked;

Content = new StackLayout
{
Padding = 20,
Children =
{
new Label { Text = "Tab 2", FontSize = 18, AutomationId = "Tab2Content" },
pushModalButton
}
};
}

async void OnPushModalClicked(object sender, EventArgs e)
{
await Navigation.PushModalAsync(new Issue35756ModalPage(_tabbedPage));
}
}

public class Issue35756ModalPage : ContentPage
{
readonly TabbedPage _tabbedPage;

public Issue35756ModalPage(TabbedPage tabbedPage)
{
Title = "Modal";
_tabbedPage = tabbedPage;

var switchTabButton = new Button
{
Text = "Switch to Tab 1",
AutomationId = "SwitchToTab1Button"
};
switchTabButton.Clicked += OnSwitchToTab1Clicked;

var closeModalButton = new Button
{
Text = "Close Modal",
AutomationId = "CloseModalButton"
};
closeModalButton.Clicked += OnCloseModalClicked;

Content = new StackLayout
{
Padding = 20,
Children =
{
new Label { Text = "Modal Page", FontSize = 18, AutomationId = "ModalContent" },
switchTabButton,
closeModalButton
}
};
}

void OnSwitchToTab1Clicked(object sender, EventArgs e)
{
_tabbedPage.CurrentPage = _tabbedPage.Children[0];
}

async void OnCloseModalClicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue35756 : _IssuesUITest
{
public Issue35756(TestDevice device) : base(device) { }

public override string Issue => "OnNavigatedTo does not fire after PopModalAsync when tab was changed from inside the modal";

[Test]
[Category(UITestCategories.TabbedPage)]
public void OnNavigatedToFiresAfterPopModalWhenTabChangedFromInsideModal()
{
App.WaitForElement("Tab1Content");
Assert.That(App.WaitForElement("Tab1NavigatedToCount").GetText(), Is.EqualTo("NavigatedTo count: 1"));

App.TapTab("Tab 2");
App.WaitForElement("Tab2Content");
App.Tap("PushModalButton");
App.WaitForElement("ModalContent");

App.Tap("SwitchToTab1Button");

App.Tap("CloseModalButton");
App.WaitForElement("Tab1Content");

Assert.That(App.WaitForElement("Tab1NavigatedToCount").GetText(), Is.EqualTo("NavigatedTo count: 3"));
}
}
Loading