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
20 changes: 18 additions & 2 deletions src/Controls/src/Core/Shell/ShellSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,24 @@ static void OnCurrentItemChanged(BindableObject bindable, object oldValue, objec
{
var shellSection = (ShellSection)bindable;

var isFromHandler =
shellSection.GetContext(CurrentItemProperty)?.Values.GetSpecificity() == SetterSpecificity.FromHandler;

if (!isFromHandler &&
newValue is ShellContent newContent &&
shellSection.Parent?.Parent is Shell parentShell &&
shellSection.IsVisibleSection)
{
parentShell.NavigationManager.ProposeNavigationOutsideGotoAsync(
ShellNavigationSource.ShellContentChanged,
parentShell.CurrentItem,
shellSection,
newContent,
shellSection.Stack,
canCancel: false,
isAnimated: true);
}

if (oldValue is ShellContent oldShellItem)
oldShellItem.SendDisappearing();

Expand All @@ -1028,9 +1046,7 @@ static void OnCurrentItemChanged(BindableObject bindable, object oldValue, objec
shellSection.PresentedPageAppearing();

if (shellSection.Parent?.Parent is IShellController shell && shellSection.IsVisibleSection)
{
shell.UpdateCurrentState(ShellNavigationSource.ShellContentChanged);
}

shellSection.SendStructureChanged();

Expand Down
117 changes: 117 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue34318.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.CustomAttributes;

namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 34318, "Shell Navigating event should fire on ShellContent change", PlatformAffected.All)]
public class Issue34318 : Shell
{
Label labelA;
Label labelB;
Label navigatingCountLabel;
int navigatingCount;

public Issue34318()
{
labelA = new Label
{
Text = "Waiting",
AutomationId = "ResultLabelA"
};

labelB = new Label
{
Text = "Waiting",
AutomationId = "ResultLabelB"
};

navigatingCountLabel = new Label
{
Text = "0",
AutomationId = "NavigatingCountLabel"
};

var section = new ShellSection();

var pageA = new Issue34318_PageA(labelA);

var contentA = new ShellContent
{
Content = pageA
};

var contentB = new ShellContent
{
Content = new ContentPage
{
Title = "PageB",
Content = new VerticalStackLayout
{
Children =
{
new Label
{
Text = "Page B",
AutomationId = "PageBLabel"
},
labelB,
navigatingCountLabel
}
}
}
};

section.Items.Add(contentA);
section.Items.Add(contentB);

var item = new ShellItem();
item.Items.Add(section);

Items.Add(item);

Navigating += (_, __) =>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[major] Regression Prevention — The regression handler ignores ShellNavigatingEventArgs, so the test only proves that some Navigating event fired once. It would still pass if the fix used the wrong Source, exposed incorrect Current/Target routes, or fired after ShellSection.CurrentItem was already changed. Capture the args here and assert Source == ShellNavigationSource.ShellContentChanged, CanCancel == false, the expected current/target locations, and the selected content observed during the handler so the test protects the Shell navigation semantics, not just the event count.

{
MainThread.BeginInvokeOnMainThread(() =>
{
navigatingCount++;

labelA.Text = "Navigating";
labelB.Text = "Navigating";
navigatingCountLabel.Text = navigatingCount.ToString();
});
};
}

public class Issue34318_PageA : ContentPage
{
public Issue34318_PageA(Label label)
{
Title = "PageA";

var button = new Button
{
Text = "Change Content",
AutomationId = "ChangeContentButton"
};

button.Clicked += (s, e) =>
{
Element parent = this;

while (parent != null && parent is not ShellSection)
parent = parent.Parent;

if (parent is ShellSection section && section.Items.Count > 1)
{
section.CurrentItem = section.Items[1];
Comment thread
jpd21122012 marked this conversation as resolved.
}
};

Content = new VerticalStackLayout
{
Children = { button, label }
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

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

public override string Issue => "Shell Navigating event should fire on ShellContent change";

[Test]
[Category(UITestCategories.Shell)]
public void NavigatingFiresWhenShellContentChanges()
{
App.WaitForElement("ChangeContentButton");

App.WaitForElement("ResultLabelA");

var initialText = App.FindElement("ResultLabelA").GetText() ?? string.Empty;
Assert.That(initialText, Is.EqualTo("Waiting"));

App.Tap("ChangeContentButton");

App.WaitForElement("PageBLabel");

var result = App.WaitForTextToBePresentInElement("ResultLabelB", "Navigating");

Assert.That(result, Is.True, "Navigating event should have fired and updated the label text");

var countText = App.FindElement("NavigatingCountLabel").GetText() ?? string.Empty;

Assert.That(countText, Is.EqualTo("1"),
"Navigating event should fire exactly once, not multiple times");
}
}
Loading