Skip to content

Shell: Add duplicate route validation for sibling elements#32296

Merged
PureWeen merged 11 commits intodotnet:inflight/currentfrom
SubhikshaSf4851:fix-14000
Jan 29, 2026
Merged

Shell: Add duplicate route validation for sibling elements#32296
PureWeen merged 11 commits intodotnet:inflight/currentfrom
SubhikshaSf4851:fix-14000

Conversation

@SubhikshaSf4851
Copy link
Contributor

@SubhikshaSf4851 SubhikshaSf4851 commented Oct 30, 2025

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Root Cause

The Shell routing system allowed duplicate routes to be registered for sibling elements (e.g., two ShellContent items in the same ShellSection with route "MapPage"). This caused confusing navigation behavior where OnNavigatedTo would not be called when navigating between pages with duplicate routes.

The user discovered this was the root cause of issue #14000 and requested that MAUI throw an exception when duplicate routes are detected, to prevent this confusing scenario.

Description of Change

Added sibling-based duplicate route validation:

  1. Routing.ValidateForDuplicates(Element, string) - New validation method that:

    • Checks if a route is already assigned to a sibling element (elements with same parent)
    • Allows same route at different hierarchy levels (e.g., //one/content and //two/content)
    • Throws ArgumentException with clear error message when duplicate found
  2. BaseShellItem.Route property setter - Now calls validation before setting route

  3. 5 comprehensive unit tests - Verify:

    • Duplicate sibling routes throw exception
    • Same route in different parents is allowed (hierarchical routing)
    • Changing/removing routes frees them for reuse
    • Reassigning same route to same element is idempotent
  4. Cleanup - Removed duplicate AddTopTab() call in Issue6878 test that would now throw

This is a philosophy change:

  • Before: Duplicate routes silently accepted, caused confusing behavior
  • After: Duplicate sibling routes rejected immediately with clear error message

Key Technical Details

Sibling-based validation:

  • Only checks duplicates among elements with the same parent (element.Parent.LogicalChildrenInternal)
  • Respects Shell's hierarchical routing structure
  • No global state needed

Why sibling-based, not global?

  • Shell supports hierarchical routing where same route can exist at different levels
  • Example: //route1/content and //route2/content are both valid
  • Global tracking would incorrectly reject this valid scenario

What NOT to Do (for future agents)

  • Don't use global route tracking (HashSet) - Breaks Shell's hierarchical routing. Reviewers rejected this approach because same route at different hierarchy levels is valid.
  • Don't use ConcurrentDictionary or shared state - Not thread-safe and causes lifecycle issues (routes never removed when elements deleted)
  • Don't validate at Shell level - Validation must be at BaseShellItem.Route setter for immediate feedback

Issues Fixed

Fixes #14000

Tested the behavior in the following platforms

  • Windows
  • Android
  • iOS
  • Mac

@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Oct 30, 2025
@dotnet-policy-service
Copy link
Contributor

Hey there @@SubhikshaSf4851! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@dotnet-policy-service dotnet-policy-service bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Oct 30, 2025
@SubhikshaSf4851 SubhikshaSf4851 marked this pull request as ready for review November 3, 2025 12:19
Copilot AI review requested due to automatic review settings November 3, 2025 12:19
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds validation to prevent duplicate routes in Shell navigation and updates tests to avoid route conflicts. The main purpose is to detect and throw an exception when duplicate routes are assigned to Shell elements, while ensuring existing tests use unique routes to prevent failures.

Key changes:

  • Added duplicate route validation in the Routing system that throws an ArgumentException when duplicate routes are detected
  • Updated test cases to generate unique route names using GUIDs to avoid conflicts when tests run in the same test collection
  • Added route cleanup logic to remove routes from the tracking set when elements are removed from the Shell hierarchy

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/Controls/src/Core/Routing.cs Introduces routeSet HashSet for tracking routes and adds validation methods (ValidateForDuplicates, RemoveElementRoute, RemoveRouteFromSet) to prevent duplicate routes
src/Controls/src/Core/Shell/BaseShellItem.cs Updates Route property setter to call validation before setting route value, and cleans up routes when elements are removed
src/Controls/tests/DeviceTests/Elements/Shell/ShellTests.cs Changes hardcoded route names to unique values and dynamically determines navigation routes; adds new test case to verify duplicate route exception is thrown
src/Controls/tests/DeviceTests/Elements/Shell/ShellTabBarTests.cs Generates unique route names using GUID to prevent conflicts between test cases
src/Controls/tests/DeviceTests/Elements/Shell/ShellBasicNavigationTestCases.cs Generates unique route names with GUID and suffixes to distinguish different shell element types

Copy link
Contributor

@StephaneDelcroix StephaneDelcroix left a comment

Choose a reason for hiding this comment

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

this should be a unit test
the linked issue looks unrelated

@SubhikshaSf4851
Copy link
Contributor Author

@StephaneDelcroix The fix were made for the user comment here

SubhikshaSf4851 and others added 9 commits December 8, 2025 15:29
The test ShouldThrowsArgumentExceptionOnDuplicateRoutes doesn't require
any platform handlers - it's testing pure exception throwing logic.
This should be a unit test, not a device test.

Moved to: src/Controls/tests/Core.UnitTests/ShellTests.cs
Removed from: src/Controls/tests/DeviceTests/Elements/Shell/ShellTests.cs
- Changed from global route tracking to sibling-based duplicate detection
- Routes are now only checked for duplicates among siblings (same parent)
- This allows the same route name in different parts of the Shell hierarchy
- Removed unused ConcurrentDictionary and global route tracking
- Reverted device test changes that were workarounds for global tracking
- Added comprehensive unit tests for sibling-based validation:
  - DuplicateSiblingRoutesShouldThrowArgumentException
  - SameRouteInDifferentParentsIsAllowed
  - ChangingRouteAllowsReuseAmongSiblings
  - RemovingElementClearsRoute
  - ReassigningSameRouteToSameElementDoesNotThrow
@StephaneDelcroix
Copy link
Contributor

Changes Made to Fix Implementation

I've updated this PR to use sibling-based duplicate route detection instead of global tracking. Here's a summary of the changes:

Why the Change Was Needed

The original implementation used a global ConcurrentDictionary to track all routes, which broke legitimate Shell navigation patterns. Shell routes are hierarchical - the same route name (like "content") can exist at different levels of the hierarchy:

//flyout1/section1/content   ← "content" here
//flyout2/section2/content   ←

Global tracking would incorrectly flag this as a duplicate.

Implementation Summary

Routing.cs - New ValidateForDuplicates() method that:

  • Only checks for duplicates among sibling elements (same parent)
  • Skips validation for non-user-defined routes (auto-generated ones)
  • Returns early if reassigning the same route to the same element

BaseShellItem.cs - Route property setter calls ValidateForDuplicates() before setting the value

Test Coverage

Added 5 unit tests in ShellTests.cs:

  1. DuplicateSiblingRoutesShouldThrowArgumentException - Verifies exception for duplicate sibling routes
  2. SameRouteInDifferentParentsIsAllowed - Confirms hierarchical routes work correctly
  3. ChangingRouteAllowsReuseAmongSiblings - Route can be reassigned after changing
  4. RemovingElementClearsRoute - Removed elements free up their routes
  5. ReassigningSameRouteToSameElementDoesNotThrow - Idempotent route assignment

All 85 Shell unit tests pass with this implementation.

Note on Issue Reference

The PR description references #14000, but that issue is about "OnNavigatedTo not being called" which appears unrelated to duplicate route detection. You may want to clarify which issue this PR actually addresses, or create a new issue specifically for duplicate route detection if one doesn't exist.

Copy link
Contributor

@StephaneDelcroix StephaneDelcroix left a comment

Choose a reason for hiding this comment

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

Approved

The sibling-based duplicate route detection implementation is correct and well-tested.

Key points:

  • Properly respects Shell's hierarchical navigation model
  • Only prevents duplicate routes among siblings (same parent)
  • Allows the same route name at different hierarchy levels (e.g., //one/content and //two/content)
  • All 85 Shell unit tests pass
  • 5 new comprehensive unit tests cover the feature

The implementation is minimal, focused, and doesn't break existing functionality.

rmarinho
rmarinho previously approved these changes Jan 7, 2026
@rmarinho
Copy link
Member

rmarinho commented Jan 7, 2026

/azp run maui-pr-uitests

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@rmarinho
Copy link
Member

rmarinho commented Jan 7, 2026

/azp run maui-pr-devicetests

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@kubaflo
Copy link
Contributor

kubaflo commented Jan 26, 2026

🤖 AI Summary

📊 Expand Full Review
🔍 Pre-Flight — Context & Validation
📝 Review SessionRemoved duplicate AddTopTab call in Issue6878 shell test case · a1a441e

Root Cause of Original Bug:
User had duplicate routes registered for different Shell pages (both "MapPage" and "MapsUIPage" had route "MapPage"). This caused OnNavigatedTo to not be called when navigating between these pages.

Feature Request from Issue Comments:
After the user discovered the root cause was duplicate routes, they requested (comment #1474008920):

"Throw exception on duplicate route on FlyoutItems in AppShell"

This would prevent the confusing behavior they experienced and make debugging easier.

Steps to Reproduce Original Issue:

  1. Create Shell with two pages that have the same route name
  2. Navigate between them
  3. Observe that OnNavigatedTo is not called on the second page

Platforms Affected:

  • iOS
  • Android
  • Windows
  • MacCatalyst

Regression Info:
Not a regression - this is a new feature to validate duplicate routes and throw an exception.


🧪 Tests — Verification
📝 Review SessionRemoved duplicate AddTopTab call in Issue6878 shell test case · a1a441e

Status: ✅ COMPLETE

  • PR includes unit tests
  • Tests verify the validation logic
  • Tests follow naming convention

Test Files:

  • Unit Tests: src/Controls/tests/Core.UnitTests/ShellTests.cs (+118 lines, 5 tests)

Tests Added:

  1. DuplicateSiblingRoutesShouldThrowArgumentException - Verifies exception for duplicate sibling routes ✅ PASS
  2. SameRouteInDifferentParentsIsAllowed - Confirms hierarchical routes work correctly ✅ PASS
  3. ChangingRouteAllowsReuseAmongSiblings - Route can be reassigned after changing ✅ PASS
  4. RemovingElementClearsRoute - Removed elements free up their routes ✅ PASS
  5. ReassigningSameRouteToSameElementDoesNotThrow - Idempotent route assignment ✅ PASS

Test Run Results:
All 5 tests passed successfully. Tests verify the sibling-based duplicate detection logic works correctly.


🚦 Gate — Test Verification
📝 Review SessionRemoved duplicate AddTopTab call in Issue6878 shell test case · a1a441e

Status: ✅ PASSED

  • Tests verify the validation logic works correctly

Result: PASSED ✅

Validation Details:
This PR adds a new feature (duplicate route validation), not a bug fix. The Gate verification confirms:

  1. Duplicate Detection Works: DuplicateSiblingRoutesShouldThrowArgumentException test confirms that setting duplicate routes among siblings throws ArgumentException with correct error message
  2. Hierarchical Routes Allowed: SameRouteInDifferentParentsIsAllowed test confirms same route can exist at different hierarchy levels
  3. Route Lifecycle Works: Tests confirm changing/removing routes correctly frees them for reuse
  4. Idempotent Assignment: Reassigning same route to same element doesn't throw

All 5 unit tests pass, confirming the sibling-based validation implementation works as designed.

Platform Tested: Unit tests (cross-platform)


🔧 Fix — Analysis & Comparison
📝 Review SessionRemoved duplicate AddTopTab call in Issue6878 shell test case · a1a441e

Status: ▶️ IN PROGRESS

Root Cause Analysis:
This is a feature implementation, not a bug fix. The original issue (#14000) was about OnNavigatedTo not being called when navigating between pages. The user discovered the root cause was having duplicate routes registered for different Shell pages. After finding this, they requested (comment #1474008920) that MAUI throw an exception when duplicate routes are detected, to prevent this confusing behavior.

Key Insight:
The PR implements sibling-based validation (only checks duplicates among elements with same parent). This allows the same route to exist at different hierarchy levels (e.g., //one/content and //two/content), which is valid in Shell's hierarchical routing.

Alternative approaches to consider:

  1. Global route tracking (rejected by reviewers - breaks hierarchical routing)
  2. Validation at different lifecycle points (constructor, property change, added to parent)
  3. Different scoping rules (siblings vs. global vs. shell-wide)
# Source Approach Test Result Files Changed Notes
PR PR #32296 Sibling-based duplicate detection: validate routes only among elements with same parent, allows hierarchical routing ✅ PASS (Gate) Routing.cs (+43), BaseShellItem.cs (+5) Revised approach after feedback - addresses all reviewer concerns

Note: try-fix candidates (1, 2, 3...) will be added below as they are explored.

Exhausted: Yes (skipped try-fix - feature implementation with validated design)
Selected Fix: PR's fix

Reasoning:
This PR implements a new feature (duplicate route validation) rather than fixing a bug. The sibling-based validation approach was chosen after extensive review:

  1. Alternative already evaluated: Reviewers (jsuarezruiz, StephaneDelcroix) already explored and rejected global route tracking approach
  2. Design is correct: Sibling-based validation correctly handles Shell's hierarchical routing while preventing problematic duplicates
  3. Implementation is minimal: Changes are surgical (43 lines validation logic + 5 lines to call it)
  4. All tests pass: 5 comprehensive tests verify the validation works correctly

Why PR's fix is best:

  • ✅ Respects Shell's hierarchical nature (allows same route at different levels)
  • ✅ Prevents actual problem (duplicate routes among siblings)
  • ✅ No global state needed
  • ✅ Validation at property setter (immediate feedback)
  • ✅ Clear error messages with helpful context

try-fix exploration would likely propose already-rejected alternatives (global tracking) or over-engineered solutions (validation frameworks, dependency injection). The PR's fix is the simplest correct solution.


📋 Report — Final Recommendation
📝 Review SessionRemoved duplicate AddTopTab call in Issue6878 shell test case · a1a441e

Status: ✅ COMPLETE

Verdict: ✅ APPROVE - Ready to Merge

Summary:
PR has been updated with excellent title and description. Code implementation is solid with comprehensive tests. Sibling-based validation correctly handles Shell's hierarchical routing. Ready to merge.

What Works ✅

  1. Title: Shell: Add duplicate route validation for sibling elements - Clear, accurate, follows conventions
  2. Description: Comprehensive with root cause, technical details, "What NOT to do" section
  3. Implementation: Sibling-based validation correctly handles Shell's hierarchical routing
  4. Tests: 5 comprehensive unit tests cover all validation scenarios
  5. Code Quality: Minimal, surgical changes (48 lines of validation logic)
  6. Documentation: Rejected approaches documented for future developers

Updates Applied ✅

PR author successfully updated the PR based on review feedback:

  • ✅ Fixed title grammar and clarity
  • ✅ Replaced stale description with accurate sibling-based validation description
  • ✅ Added root cause explanation
  • ✅ Added "What NOT to do" section documenting rejected global HashSet approach
  • ✅ Added technical rationale for sibling-based vs global validation
  • ✅ Added philosophy change (before/after behavior)

Why This PR is Excellent

For future developers/agents:

  • Commit message will explain why sibling-based validation was chosen over global tracking
  • Documents that global HashSet approach was tried and rejected
  • Explains Shell's hierarchical routing model (same route at different levels is valid)
  • Prevents future agents from repeating rejected approaches

Final Recommendation

✅ APPROVE FOR MERGE

No further changes needed. The PR is exemplary in both implementation and documentation.


@kubaflo
Copy link
Contributor

kubaflo commented Jan 26, 2026

📋 PR Finalization Review

Review #1: Finalization review ✅ Ready

Title ✅ Good

Current: Shell: Add duplicate route validation for sibling elements

Description ✅ Excellent

| Criteria | Status | Notes |
|

✏️ Recommended PR Description

Click to expand full recommended description
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you!

### Root Cause

The Shell routing system allowed duplicate routes to be registered for sibling elements (e.g., two ShellContent items in the same ShellSection with route "MapPage"). This caused confusing navigation behavior where `OnNavigatedTo` would not be called when navigating between pages with duplicate routes.

The user discovered this was the root cause of issue #14000 and requested that MAUI throw an exception when duplicate routes are detected, to prevent this confusing scenario.

### Description of Change

Added **sibling-based duplicate route validation**:

1. **`Routing.ValidateForDuplicates(Element, string)`** - New validation method that:
   - Checks if a route is already assigned to a sibling element (elements with same parent)
   - Allows same route at different hierarchy levels (e.g., `//one/content` and `//two/content`)
   - Throws `ArgumentException` with clear error message when duplicate found

2. **`BaseShellItem.Route` property setter** - Now calls validation before setting route

3. **5 comprehensive unit tests** - Verify:
   - Duplicate sibling routes throw exception
   - Same route in different parents is allowed (hierarchical routing)
   - Changing/removing routes frees them for reuse
   - Reassigning same route to same element is idempotent

4. **Cleanup** - Removed duplicate `AddTopTab()` call in Issue6878 test that would now throw

**This is a philosophy change:**
- **Before:** Duplicate routes silently accepted, caused confusing behavior
- **After:** Duplicate sibling routes rejected immediately with clear error message

### Key Technical Details

**Sibling-based validation:**
- Only checks duplicates among elements with the same parent (`element.Parent.LogicalChildrenInternal`)
- Respects Shell's hierarchical routing structure
- No global state needed

**Why sibling-based, not global?**
- Shell supports hierarchical routing where same route can exist at different levels
- Example: `//route1/content` and `//route2/content` are both valid
- Global tracking would incorrectly reject this valid scenario

### What NOT to Do (for future agents)

-**Don't use global route tracking (HashSet<string>)** - Breaks Shell's hierarchical routing. Reviewers rejected this approach because same route at different hierarchy levels is valid.
-**Don't use ConcurrentDictionary or shared state** - Not thread-safe and causes lifecycle issues (routes never removed when elements deleted)
-**Don't validate at Shell level** - Validation must be at BaseShellItem.Route setter for immediate feedback

### Issues Fixed

Fixes #14000

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

Copy the above and replace the current PR description.

@kubaflo kubaflo changed the title Fixed Exception should thrown on Duplicate route Issue Shell: Add duplicate route validation for sibling elements Jan 26, 2026
@PureWeen PureWeen changed the base branch from main to inflight/current January 29, 2026 20:54
@PureWeen PureWeen merged commit 456e69a into dotnet:inflight/current Jan 29, 2026
13 of 23 checks passed
PureWeen pushed a commit that referenced this pull request Jan 29, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

The Shell routing system allowed duplicate routes to be registered for
sibling elements (e.g., two ShellContent items in the same ShellSection
with route "MapPage"). This caused confusing navigation behavior where
`OnNavigatedTo` would not be called when navigating between pages with
duplicate routes.

The user discovered this was the root cause of issue #14000 and
requested that MAUI throw an exception when duplicate routes are
detected, to prevent this confusing scenario.

### Description of Change

Added **sibling-based duplicate route validation**:

1. **`Routing.ValidateForDuplicates(Element, string)`** - New validation
method that:
- Checks if a route is already assigned to a sibling element (elements
with same parent)
- Allows same route at different hierarchy levels (e.g., `//one/content`
and `//two/content`)
- Throws `ArgumentException` with clear error message when duplicate
found

2. **`BaseShellItem.Route` property setter** - Now calls validation
before setting route

3. **5 comprehensive unit tests** - Verify:
   - Duplicate sibling routes throw exception
   - Same route in different parents is allowed (hierarchical routing)
   - Changing/removing routes frees them for reuse
   - Reassigning same route to same element is idempotent

4. **Cleanup** - Removed duplicate `AddTopTab()` call in Issue6878 test
that would now throw

**This is a philosophy change:**
- **Before:** Duplicate routes silently accepted, caused confusing
behavior
- **After:** Duplicate sibling routes rejected immediately with clear
error message

### Key Technical Details

**Sibling-based validation:**
- Only checks duplicates among elements with the same parent
(`element.Parent.LogicalChildrenInternal`)
- Respects Shell's hierarchical routing structure
- No global state needed

**Why sibling-based, not global?**
- Shell supports hierarchical routing where same route can exist at
different levels
- Example: `//route1/content` and `//route2/content` are both valid
- Global tracking would incorrectly reject this valid scenario

### What NOT to Do (for future agents)

- ❌ **Don't use global route tracking (HashSet<string>)** - Breaks
Shell's hierarchical routing. Reviewers rejected this approach because
same route at different hierarchy levels is valid.
- ❌ **Don't use ConcurrentDictionary or shared state** - Not thread-safe
and causes lifecycle issues (routes never removed when elements deleted)
- ❌ **Don't validate at Shell level** - Validation must be at
BaseShellItem.Route setter for immediate feedback

### Issues Fixed

Fixes #14000

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

---------

Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
PureWeen pushed a commit that referenced this pull request Feb 2, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

The Shell routing system allowed duplicate routes to be registered for
sibling elements (e.g., two ShellContent items in the same ShellSection
with route "MapPage"). This caused confusing navigation behavior where
`OnNavigatedTo` would not be called when navigating between pages with
duplicate routes.

The user discovered this was the root cause of issue #14000 and
requested that MAUI throw an exception when duplicate routes are
detected, to prevent this confusing scenario.

### Description of Change

Added **sibling-based duplicate route validation**:

1. **`Routing.ValidateForDuplicates(Element, string)`** - New validation
method that:
- Checks if a route is already assigned to a sibling element (elements
with same parent)
- Allows same route at different hierarchy levels (e.g., `//one/content`
and `//two/content`)
- Throws `ArgumentException` with clear error message when duplicate
found

2. **`BaseShellItem.Route` property setter** - Now calls validation
before setting route

3. **5 comprehensive unit tests** - Verify:
   - Duplicate sibling routes throw exception
   - Same route in different parents is allowed (hierarchical routing)
   - Changing/removing routes frees them for reuse
   - Reassigning same route to same element is idempotent

4. **Cleanup** - Removed duplicate `AddTopTab()` call in Issue6878 test
that would now throw

**This is a philosophy change:**
- **Before:** Duplicate routes silently accepted, caused confusing
behavior
- **After:** Duplicate sibling routes rejected immediately with clear
error message

### Key Technical Details

**Sibling-based validation:**
- Only checks duplicates among elements with the same parent
(`element.Parent.LogicalChildrenInternal`)
- Respects Shell's hierarchical routing structure
- No global state needed

**Why sibling-based, not global?**
- Shell supports hierarchical routing where same route can exist at
different levels
- Example: `//route1/content` and `//route2/content` are both valid
- Global tracking would incorrectly reject this valid scenario

### What NOT to Do (for future agents)

- ❌ **Don't use global route tracking (HashSet<string>)** - Breaks
Shell's hierarchical routing. Reviewers rejected this approach because
same route at different hierarchy levels is valid.
- ❌ **Don't use ConcurrentDictionary or shared state** - Not thread-safe
and causes lifecycle issues (routes never removed when elements deleted)
- ❌ **Don't validate at Shell level** - Validation must be at
BaseShellItem.Route setter for immediate feedback

### Issues Fixed

Fixes #14000

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

---------

Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
github-actions bot pushed a commit that referenced this pull request Feb 4, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

The Shell routing system allowed duplicate routes to be registered for
sibling elements (e.g., two ShellContent items in the same ShellSection
with route "MapPage"). This caused confusing navigation behavior where
`OnNavigatedTo` would not be called when navigating between pages with
duplicate routes.

The user discovered this was the root cause of issue #14000 and
requested that MAUI throw an exception when duplicate routes are
detected, to prevent this confusing scenario.

### Description of Change

Added **sibling-based duplicate route validation**:

1. **`Routing.ValidateForDuplicates(Element, string)`** - New validation
method that:
- Checks if a route is already assigned to a sibling element (elements
with same parent)
- Allows same route at different hierarchy levels (e.g., `//one/content`
and `//two/content`)
- Throws `ArgumentException` with clear error message when duplicate
found

2. **`BaseShellItem.Route` property setter** - Now calls validation
before setting route

3. **5 comprehensive unit tests** - Verify:
   - Duplicate sibling routes throw exception
   - Same route in different parents is allowed (hierarchical routing)
   - Changing/removing routes frees them for reuse
   - Reassigning same route to same element is idempotent

4. **Cleanup** - Removed duplicate `AddTopTab()` call in Issue6878 test
that would now throw

**This is a philosophy change:**
- **Before:** Duplicate routes silently accepted, caused confusing
behavior
- **After:** Duplicate sibling routes rejected immediately with clear
error message

### Key Technical Details

**Sibling-based validation:**
- Only checks duplicates among elements with the same parent
(`element.Parent.LogicalChildrenInternal`)
- Respects Shell's hierarchical routing structure
- No global state needed

**Why sibling-based, not global?**
- Shell supports hierarchical routing where same route can exist at
different levels
- Example: `//route1/content` and `//route2/content` are both valid
- Global tracking would incorrectly reject this valid scenario

### What NOT to Do (for future agents)

- ❌ **Don't use global route tracking (HashSet<string>)** - Breaks
Shell's hierarchical routing. Reviewers rejected this approach because
same route at different hierarchy levels is valid.
- ❌ **Don't use ConcurrentDictionary or shared state** - Not thread-safe
and causes lifecycle issues (routes never removed when elements deleted)
- ❌ **Don't validate at Shell level** - Validation must be at
BaseShellItem.Route setter for immediate feedback

### Issues Fixed

Fixes #14000

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

---------

Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
github-actions bot pushed a commit that referenced this pull request Feb 8, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

The Shell routing system allowed duplicate routes to be registered for
sibling elements (e.g., two ShellContent items in the same ShellSection
with route "MapPage"). This caused confusing navigation behavior where
`OnNavigatedTo` would not be called when navigating between pages with
duplicate routes.

The user discovered this was the root cause of issue #14000 and
requested that MAUI throw an exception when duplicate routes are
detected, to prevent this confusing scenario.

### Description of Change

Added **sibling-based duplicate route validation**:

1. **`Routing.ValidateForDuplicates(Element, string)`** - New validation
method that:
- Checks if a route is already assigned to a sibling element (elements
with same parent)
- Allows same route at different hierarchy levels (e.g., `//one/content`
and `//two/content`)
- Throws `ArgumentException` with clear error message when duplicate
found

2. **`BaseShellItem.Route` property setter** - Now calls validation
before setting route

3. **5 comprehensive unit tests** - Verify:
   - Duplicate sibling routes throw exception
   - Same route in different parents is allowed (hierarchical routing)
   - Changing/removing routes frees them for reuse
   - Reassigning same route to same element is idempotent

4. **Cleanup** - Removed duplicate `AddTopTab()` call in Issue6878 test
that would now throw

**This is a philosophy change:**
- **Before:** Duplicate routes silently accepted, caused confusing
behavior
- **After:** Duplicate sibling routes rejected immediately with clear
error message

### Key Technical Details

**Sibling-based validation:**
- Only checks duplicates among elements with the same parent
(`element.Parent.LogicalChildrenInternal`)
- Respects Shell's hierarchical routing structure
- No global state needed

**Why sibling-based, not global?**
- Shell supports hierarchical routing where same route can exist at
different levels
- Example: `//route1/content` and `//route2/content` are both valid
- Global tracking would incorrectly reject this valid scenario

### What NOT to Do (for future agents)

- ❌ **Don't use global route tracking (HashSet<string>)** - Breaks
Shell's hierarchical routing. Reviewers rejected this approach because
same route at different hierarchy levels is valid.
- ❌ **Don't use ConcurrentDictionary or shared state** - Not thread-safe
and causes lifecycle issues (routes never removed when elements deleted)
- ❌ **Don't validate at Shell level** - Validation must be at
BaseShellItem.Route setter for immediate feedback

### Issues Fixed

Fixes #14000

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

---------

Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
PureWeen pushed a commit that referenced this pull request Feb 9, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

The Shell routing system allowed duplicate routes to be registered for
sibling elements (e.g., two ShellContent items in the same ShellSection
with route "MapPage"). This caused confusing navigation behavior where
`OnNavigatedTo` would not be called when navigating between pages with
duplicate routes.

The user discovered this was the root cause of issue #14000 and
requested that MAUI throw an exception when duplicate routes are
detected, to prevent this confusing scenario.

### Description of Change

Added **sibling-based duplicate route validation**:

1. **`Routing.ValidateForDuplicates(Element, string)`** - New validation
method that:
- Checks if a route is already assigned to a sibling element (elements
with same parent)
- Allows same route at different hierarchy levels (e.g., `//one/content`
and `//two/content`)
- Throws `ArgumentException` with clear error message when duplicate
found

2. **`BaseShellItem.Route` property setter** - Now calls validation
before setting route

3. **5 comprehensive unit tests** - Verify:
   - Duplicate sibling routes throw exception
   - Same route in different parents is allowed (hierarchical routing)
   - Changing/removing routes frees them for reuse
   - Reassigning same route to same element is idempotent

4. **Cleanup** - Removed duplicate `AddTopTab()` call in Issue6878 test
that would now throw

**This is a philosophy change:**
- **Before:** Duplicate routes silently accepted, caused confusing
behavior
- **After:** Duplicate sibling routes rejected immediately with clear
error message

### Key Technical Details

**Sibling-based validation:**
- Only checks duplicates among elements with the same parent
(`element.Parent.LogicalChildrenInternal`)
- Respects Shell's hierarchical routing structure
- No global state needed

**Why sibling-based, not global?**
- Shell supports hierarchical routing where same route can exist at
different levels
- Example: `//route1/content` and `//route2/content` are both valid
- Global tracking would incorrectly reject this valid scenario

### What NOT to Do (for future agents)

- ❌ **Don't use global route tracking (HashSet<string>)** - Breaks
Shell's hierarchical routing. Reviewers rejected this approach because
same route at different hierarchy levels is valid.
- ❌ **Don't use ConcurrentDictionary or shared state** - Not thread-safe
and causes lifecycle issues (routes never removed when elements deleted)
- ❌ **Don't validate at Shell level** - Validation must be at
BaseShellItem.Route setter for immediate feedback

### Issues Fixed

Fixes #14000

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

---------

Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
github-actions bot pushed a commit that referenced this pull request Feb 9, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

The Shell routing system allowed duplicate routes to be registered for
sibling elements (e.g., two ShellContent items in the same ShellSection
with route "MapPage"). This caused confusing navigation behavior where
`OnNavigatedTo` would not be called when navigating between pages with
duplicate routes.

The user discovered this was the root cause of issue #14000 and
requested that MAUI throw an exception when duplicate routes are
detected, to prevent this confusing scenario.

### Description of Change

Added **sibling-based duplicate route validation**:

1. **`Routing.ValidateForDuplicates(Element, string)`** - New validation
method that:
- Checks if a route is already assigned to a sibling element (elements
with same parent)
- Allows same route at different hierarchy levels (e.g., `//one/content`
and `//two/content`)
- Throws `ArgumentException` with clear error message when duplicate
found

2. **`BaseShellItem.Route` property setter** - Now calls validation
before setting route

3. **5 comprehensive unit tests** - Verify:
   - Duplicate sibling routes throw exception
   - Same route in different parents is allowed (hierarchical routing)
   - Changing/removing routes frees them for reuse
   - Reassigning same route to same element is idempotent

4. **Cleanup** - Removed duplicate `AddTopTab()` call in Issue6878 test
that would now throw

**This is a philosophy change:**
- **Before:** Duplicate routes silently accepted, caused confusing
behavior
- **After:** Duplicate sibling routes rejected immediately with clear
error message

### Key Technical Details

**Sibling-based validation:**
- Only checks duplicates among elements with the same parent
(`element.Parent.LogicalChildrenInternal`)
- Respects Shell's hierarchical routing structure
- No global state needed

**Why sibling-based, not global?**
- Shell supports hierarchical routing where same route can exist at
different levels
- Example: `//route1/content` and `//route2/content` are both valid
- Global tracking would incorrectly reject this valid scenario

### What NOT to Do (for future agents)

- ❌ **Don't use global route tracking (HashSet<string>)** - Breaks
Shell's hierarchical routing. Reviewers rejected this approach because
same route at different hierarchy levels is valid.
- ❌ **Don't use ConcurrentDictionary or shared state** - Not thread-safe
and causes lifecycle issues (routes never removed when elements deleted)
- ❌ **Don't validate at Shell level** - Validation must be at
BaseShellItem.Route setter for immediate feedback

### Issues Fixed

Fixes #14000

### Tested the behavior in the following platforms

- [x] Windows
- [x] Android
- [x] iOS
- [x] Mac

---------

Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
PureWeen added a commit that referenced this pull request Feb 10, 2026
.NET MAUI inflight/candidate introduces significant improvements across
all platforms with focus on quality, performance, and developer
experience. This release includes 20 commits with various improvements,
bug fixes, and enhancements.


## Blazor
- Fix for BlazorWebView Back Navigation Issues on Android 13+ After
Predictive Back Gesture Changes by @SuthiYuvaraj in
#33213
  <details>
  <summary>🔧 Fixes</summary>

- [Back navigation different between .net 9 and .net 10 blazor
hybrid](#32767)
  </details>

## CollectionView
- [Android] Fix for CollectionView.EmptyView does not remeasure its
height when the parent layout changes dynamically, causing incorrect
sizing. by @BagavathiPerumal in
#33559
  <details>
  <summary>🔧 Fixes</summary>

- [`CollectionView.EmptyView` does not remeasure its height when the
parent layout changes dynamically, causing incorrect
sizing.](#33324)
  </details>

- [Android] Fixed CollectionView reordering last item by @vitalii-vov in
#17825
  <details>
  <summary>🔧 Fixes</summary>

- [Android app crashes when dragging into
CollectionView](#17823)
  </details>

## DateTimePicker
- [iOS] Fix VoiceOver focus not shifting to Picker/DatePicker/TimePicker
popups by @kubaflo in #33152
  <details>
  <summary>🔧 Fixes</summary>

- [Voiceover does not automatically shift focus to the "Category" popup
when it opens.: A11y_Developer balance version .NET
10_Project_ScreenReader](#30746)
  </details>

## Dialogalert
- [iOS 26] Fix DisplayPromptAsync maxLength not enforced due to new
multi-range delegate by @Shalini-Ashokan in
#33616
  <details>
  <summary>🔧 Fixes</summary>

- [[iOS 26.1] DisplayPromptAsync ignores maxLength and does not respect
RTL FlowDirection](#33549)
  </details>

## Flyout
- [iOS] Shell: Account for SafeArea when positioning flyout footer by
@kubaflo in #32891
  <details>
  <summary>🔧 Fixes</summary>

- [[IOS] Footer not displaying in iOS when StackOrientation.Horizontal
is set on FlyoutFooter](#26395)
  </details>

## Fonts
- Hide obsolete FontSize values from IDE autocomplete by @noiseonwires
in #33694

## Gestures
- Android pan fixes by @BurningLights in
#21547
  <details>
  <summary>🔧 Fixes</summary>

- [Flickering occurs while updating the width of ContentView through
PanGestureRecognizer.](#20772)
  </details>

## Navigation
- Shell: Add duplicate route validation for sibling elements by
@SubhikshaSf4851 in #32296
  <details>
  <summary>🔧 Fixes</summary>

- [OnNavigatedTo is not called when navigating from a specific
page](#14000)
  </details>

## Picker
- Improved Unfocus support for Picker on Mac Catalyst by @kubaflo in
#33127
  <details>
  <summary>🔧 Fixes</summary>

- [When using voiceover unable to access expanded list of project combo
box: A11y_.NET maui_user can creat a tak_Screen
reader](#30897)
- [Task and Project controls are not accessible with keyboard:A11y_.NET
maui_User can create a new
task_Keyboard](#30891)
  </details>

## SafeArea
- [iOS] SafeArea: Return Empty for non-ISafeAreaView views (opt-in
model) by @praveenkumarkarunanithi in
#33526
  <details>
  <summary>🔧 Fixes</summary>

- [[iOS] SafeArea is not applied when a ContentPage uses a
ControlTemplate](#33458)
  </details>

## Shell
- [iOS] Fix ObjectDisposedException in TraitCollectionDidChange on
window disposal by @jeremy-visionaid in
#33353
  <details>
  <summary>🔧 Fixes</summary>

- [Intermittent crash on exit on MacCatalyst -
ObjectDisposedException](#33352)
  </details>

- [Issue-Resolver] Explicit fallback for BackButtonBehavior lookup by
@kubaflo in #33204
  <details>
  <summary>🔧 Fixes</summary>

- [Setting BackButtonBehavior to not visible or not enabled does not
work](#28570)
- [BackButtonBehavior not
bound](#33139)
  </details>

## Templates
- [Templates] Remove redundant SemanticProperties.Description attribute
by @kubaflo in #33621
  <details>
  <summary>🔧 Fixes</summary>

- [Task and Project controls are not accessible with keyboard:A11y_.NET
maui_User can create a new
task_Keyboard](#30891)
- [Unable to select "Tags" when Voiceover is turned on.: A11y_Developer
balance version .NET
10_Project_ScreenReader](#30749)
  </details>

## Theme
- [Windows] Fix runtime theme update for controls and TitleBar by
@Tamilarasan-Paranthaman in #31714
  <details>
  <summary>🔧 Fixes</summary>

- [[Windows][MacOS?] Change title bar color when switching light/dark
theme at runtime](#12507)
- [OS system components ignore app
theme](#22058)
- [[Mac Catalyst][Windows] TitleBar not reacting on UserAppTheme
changes](#30518)
- [In dark theme "Back" and "hamburger" button icon color contrast with
background color is less than 3:1: A11y_.NET maui_User can get all the
insights of Dashboard_Non text
Contrast](#30807)
- [`Switch` is invisible on `PointOver` when theme has
changed](#31819)
  </details>

## Theming
- [XSG] Fix Style Setters referencing source-generated bindable
properties by @simonrozsival in
#33562

## Titlebar
- [Windows] Fix TitleBar.IsVisible = false the caption buttons become
unresponsive by @devanathan-vaithiyanathan in
#33256
  <details>
  <summary>🔧 Fixes</summary>

- [When TitleBar.IsVisible = false the caption buttons become
unresponsive on Windows](#33171)
  </details>

## WebView
- Fix WebView JavaScript string escaping for backslashes and quotes by
@StephaneDelcroix in #33726

## Xaml
- [XSG] Fix NaN value in XAML generating invalid code by
@StephaneDelcroix in #33533
  <details>
  <summary>🔧 Fixes</summary>

- [[XSG] NaN value in XAML generates invalid
code](#33532)
  </details>


<details>
<summary>📦 Other (1)</summary>

- Remove InternalsVisibleTo attributes for .NET MAUI Community Toolkit
by @jfversluis via @Copilot in #33442

</details>
**Full Changelog**:
main...inflight/candidate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OnNavigatedTo is not called when navigating from a specific page

6 participants

Comments