Shell: Update flyout behavior when items are dynamically replaced#28241
Shell: Update flyout behavior when items are dynamically replaced#28241Vignesh-SF3580 wants to merge 12 commits intodotnet:mainfrom
Conversation
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28078.cs
Outdated
Show resolved
Hide resolved
|
/rebase |
3919ece to
6630366
Compare
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28078.cs
Outdated
Show resolved
Hide resolved
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
|
Just confirming that this PR fixes my issue. shell.ChildAdded += (_, _) =>
{
if (mcShell.Items.Count == 2)
{
NotifyFlyoutBehaviorObservers(mcShell);
}
};
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "NotifyFlyoutBehaviorObservers")]
extern static void NotifyFlyoutBehaviorObservers(Shell shell);So I'm not really blocked. Still, would be nice to have this issue fixed :) |
33b1d2f to
5ef3efe
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes a critical issue where Shell flyout menu icons disappear or cause crashes on Android after clearing and adding items to Shell.Items. The fix ensures that flyout behavior is properly updated when items are re-added after being cleared.
Key Changes
- Added
_isItemsClearedflag to track when items have been cleared from a collection - Added logic to notify flyout behavior observers when the second item is added after a clear operation
- Added comprehensive UI tests with snapshots for Android, iOS, Windows, and Mac platforms
Reviewed changes
Copilot reviewed 3 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/Controls/src/Core/Shell/ShellElementCollection.cs |
Core fix: Tracks cleared state and notifies flyout behavior observers when items are re-added |
src/Controls/tests/TestCases.HostApp/Issues/Issue28078.cs |
Test page that reproduces the issue by clearing and adding Shell items |
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28078.cs |
NUnit test implementation that verifies the fix works |
src/Controls/tests/TestCases.Android.Tests/snapshots/android/ShellFlyoutMenuCrash.png |
Visual verification snapshot for Android |
src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ShellFlyoutMenuCrash.png |
Visual verification snapshot for iOS |
src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShellFlyoutMenuCrash.png |
Visual verification snapshot for Windows |
src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/ShellFlyoutMenuCrash.png |
Visual verification snapshot for Mac |
| // When items are cleared, the flyout behavior is set to disabled state. When adding items again, we need to update the flyout behavior. The flyout state should be updated only when the second item is added to the view. | ||
| if (_isItemsCleared && Count == 2 && this is ShellItemCollection shellItemCollection) | ||
| { | ||
| var shell = shellItemCollection[0].Parent as Shell; | ||
| shell?.NotifyFlyoutBehaviorObservers(); | ||
| _isItemsCleared = false; | ||
| } |
There was a problem hiding this comment.
[nitpick] The comment and logic would be clearer if restructured. The comment states "The flyout state should be updated only when the second item is added" but the condition Count == 2 actually means "when the second item has been added" (after the add operation completes). Consider rephrasing to: "When items are cleared, the flyout behavior is set to disabled state. When adding items again, update the flyout behavior after the second item is added."
Additionally, the variable name _isItemsCleared doesn't clearly indicate that it's tracking whether the flyout behavior needs to be updated. Consider renaming to _needsFlyoutBehaviorUpdate for better clarity.
| var shell = shellItemCollection[0].Parent as Shell; | ||
| shell?.NotifyFlyoutBehaviorObservers(); | ||
| _isItemsCleared = false; | ||
| } |
There was a problem hiding this comment.
The fix specifically checks this is ShellItemCollection but the _isItemsCleared flag is set in the base ShellElementCollection class for all collection types. If a non-ShellItemCollection is cleared and items are added, the flag will be set to true but never reset to false. This could lead to unexpected behavior.
Consider either:
- Moving the flag to
ShellItemCollectionspecifically, or - Resetting the flag in an else block:
else { _isItemsCleared = false; }
This ensures the flag is properly managed for all collection types.
| } | |
| } | |
| else if (_isItemsCleared) | |
| { | |
| _isItemsCleared = false; | |
| } |
🤖 AI Summary📊 Expand Full Review🔍 Pre-Flight — Context & Validation📝 Review Session — updated ShellElementCollection.cs ·
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #28241 | Add _isItemsCleared flag; set on Clear(); notify flyout behavior when Count==2 after clear |
⏳ PENDING (Gate) | ShellElementCollection.cs (+10) |
Original PR fix |
PR's Fix Approach
The fix adds state tracking to ShellElementCollection:
- New flag:
bool _isItemsClearedfield added to track when items are cleared - Set on Clear(): Flag set to
trueinClear()method (line 123) - Check on Add(): When items are added after clear, check if
Count == 2andthis is ShellItemCollection - Notify observers: Call
shell?.NotifyFlyoutBehaviorObservers()to update flyout behavior - Reset flag: Set
_isItemsCleared = falseafter notification
Key logic: The fix specifically targets the second item addition (Count == 2) because that's when the flyout menu becomes relevant (flyout needs at least 2 pages to be meaningful).
Reviewers' Concerns
Copilot's concerns:
- Variable naming:
_isItemsClearedcould be clearer as_needsFlyoutBehaviorUpdate - Flag scope: Flag is in base class but only checked for
ShellItemCollection- potential leak for other collection types
🚦 Gate — Test Verification
📝 Review Session — updated ShellElementCollection.cs · 5ef3efe
Result: ✅ PASSED
Platform: android
Mode: Full Verification
Verification Results
- Tests FAIL without fix ✅ (proves tests detect the bug)
- Tests PASS with fix ✅ (proves fix resolves the issue)
Test Details
Test Configuration:
- Platform: Android
- Device: emulator-5554
- Test Filter: Issue28078
- Test Name: ShellFlyoutMenuCrash
- Category: Shell
Fix Files Validated:
src/Controls/src/Core/Shell/ShellElementCollection.cs
Execution Summary:
- Total Tests Run: 1
- Test Execution Time: ~6 seconds per run
- Build Time: ~90 seconds (initial), ~28 seconds (with fix)
Test Behavior
The test successfully validates that:
- Without fix: Clicking the flyout menu after clearing and adding items causes the expected crash/failure
- With fix: The flyout menu works correctly after clearing and adding items
This confirms the tests are properly written and catch the exact issue described in #28078.
🔧 Fix — Analysis & Comparison
📝 Review Session — updated ShellElementCollection.cs · 5ef3efe
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix (claude-sonnet-4.5) | Override Add() in ShellItemCollection to detect 1→2 transition | ✅ PASS | 1 file (ShellItemCollection.cs) | No state flag; localized to derived class; checks Count==1 before, Count==2 after |
| 2 | try-fix (claude-opus-4.6) | Notify flyout from Shell.Initialize items handler | ✅ PASS | 1 file (Shell.cs) | Add NotifyFlyoutBehaviorObservers() to existing VisibleItemsChangedInternal handler |
| 3 | try-fix (gpt-5.2) | Notify from Shell.SendFlyoutItemsChanged() | ✅ PASS | 1 file (Shell.cs) | Call NotifyFlyoutBehaviorObservers() inside SendFlyoutItemsChanged() |
| 4 | try-fix (gpt-5.2-codex) | Notify on page appearing | ❌ FAIL | 1 file (Shell.cs) | Why failed: Too late - crash happens before page appears |
| 6 | try-fix (gpt-5.2) | Track wasMulti/isMulti transitions in InnerCollectionChanged | ✅ PASS | 1 file (ShellElementCollection.cs) | More complex state tracking; handles all 0/1↔2+ transitions |
| 7 | try-fix (gpt-5.2-codex) | Override OnChildAdded in Shell.cs | ✅ PASS | 8 files (Shell.cs + 7 PublicAPI.Unshipped.txt) | Shell-level hook; requires PublicAPI updates for new protected override |
| PR | PR #28241 | State tracking + Count==2 check in InnerCollectionChanged | ✅ PASS (Gate) | 1 file (ShellElementCollection.cs) | Set _isItemsCleared flag on Clear(); check flag + Count==2 on Add() |
Cross-Pollination Results
Round 2:
| Model | Response | Action Taken |
|---|---|---|
| claude-sonnet-4.5 | NEW IDEAS: Reactive attachment, property listener, virtual OnItemsRestored, lazy validation | Declined - variations of existing approaches |
| claude-opus-4.6 | NO NEW IDEAS | N/A |
| gpt-5.2 | NEW IDEA: Track wasMulti/isMulti transitions | ✅ Implemented as Attempt 6 - PASSED |
| gpt-5.2-codex | NEW IDEA: Override OnChildAdded in Shell.cs | ✅ Implemented as Attempt 7 - PASSED |
| gemini-3-pro-preview | (Failed to respond) | Skipped after retry |
Round 3:
| Model | Response |
|---|---|
| claude-sonnet-4.5 | NEW IDEAS: Property setter interception, lazy visual tree evaluation, collection action filtering |
| claude-opus-4.6 | NO NEW IDEAS |
| gpt-5.2 | NEW IDEA: Force Reset rebuild on 1↔2 transition |
| gpt-5.2-codex | NO NEW IDEAS |
| gemini-3-pro-preview | NEW IDEA: Subscribe in ShellFlyoutItemsManager |
Exhausted: Yes (7 attempts completed; remaining ideas are variations)
Selected Fix: PR's Fix (Original)
Reasoning:
After comparing 6 passing candidates with the PR's fix, the PR's approach is the best choice for the following reasons:
1. Simplicity and Clarity:
- The PR's fix is straightforward: track when items are cleared, then notify when exactly 2 items exist
- Single boolean flag with clear set/reset points
- Easy to understand intent from the code and comment
2. Minimal Scope:
- Only modifies
ShellElementCollection.cs(1 file) - No PublicAPI changes (unlike Attempt 7)
- No Shell-level changes that might affect other behaviors
3. Precise Targeting:
- The check
_isItemsCleared && Count == 2 && this is ShellItemCollectionis very specific - Only triggers in the exact scenario that causes the bug (clear + add second item)
- Less likely to cause unintended side effects in other scenarios
4. Comparison with Alternatives:
| Candidate | Why Not Selected |
|---|---|
| #1 (Override Add) | Similar simplicity but requires overriding collection method; PR's approach keeps logic in existing event handler |
| #2 (Shell.Initialize) | Triggers on ALL items changes, not just clear+add; may cause unnecessary notifications |
| #3 (SendFlyoutItemsChanged) | Similar issue - broader scope than needed; triggers on all flyout item changes |
| #6 (wasMulti/isMulti) | More complex state tracking with additional fields; harder to understand intent |
| #7 (OnChildAdded) | Requires 8 file changes (PublicAPI updates); introduces new protected override for limited use case |
5. Test Coverage:
- PR includes comprehensive test coverage across all platforms (Android, iOS, Windows, Mac)
- Tests specifically reproduce the clear+add scenario
- Snapshots verify correct visual behavior
Root Cause Analysis
What was broken:
After Shell.Items.Clear() followed by adding new items, the flyout behavior remained in a disabled/stale state because the flyout observers were never notified to recalculate GetEffectiveFlyoutBehavior().
Why it broke:
GetEffectiveFlyoutBehavior()returnsFlyoutBehavior.DisabledwhenItems.Count <= 1- After Clear(), count is 0 → flyout disabled
- When adding items back, no code path existed to re-evaluate and notify the disabled→enabled transition
- Android's DrawerLayout required the flyout to be properly initialized before the hamburger button could work
Why the fix works:
The PR's fix detects the specific transition point (adding the second item after a clear) and calls NotifyFlyoutBehaviorObservers(), which forces all platform handlers to re-evaluate GetEffectiveFlyoutBehavior() and update their UI accordingly (show hamburger button, setup drawer layout, etc.).
Edge cases handled:
- Only triggers for
ShellItemCollection(not other shell element collections) - Only triggers when
Count == 2(the point where flyout becomes meaningful) - Only triggers after items were cleared (via
_isItemsClearedflag) - Flag is reset after notification to avoid repeated triggers
📋 Report — Final Recommendation
📝 Review Session — updated ShellElementCollection.cs · 5ef3efe
✅ Final Recommendation: APPROVE
Summary
PR #28241 successfully fixes a critical Shell crash on Android (and icon visibility issues on Windows/iOS) when clearing and re-adding Shell.Items. The fix has been thoroughly validated:
- ✅ Gate passed - Tests correctly fail without fix, pass with fix
- ✅ 6 passing alternatives explored - All use similar approach (detect 1→2 item transition)
- ✅ PR's fix is the best choice - Simplest, most targeted, minimal scope
- ✅ Comprehensive test coverage - UI tests + snapshots for all platforms
Root Cause
After Shell.Items.Clear() followed by adding new items, the flyout behavior remained in a disabled/stale state because the flyout observers were never notified to recalculate GetEffectiveFlyoutBehavior().
Why it broke:
GetEffectiveFlyoutBehavior()returnsFlyoutBehavior.DisabledwhenItems.Count <= 1- After Clear(), count is 0 → flyout disabled
- When adding items back, no code path existed to re-evaluate and notify the disabled→enabled transition
- Android's DrawerLayout required the flyout to be properly initialized before the hamburger button could work → crash: "No drawer view found with gravity LEFT"
Fix Quality
What the code does:
The fix adds state tracking to ShellElementCollection:
- Set
_isItemsCleared = truewhenClear()is called - On item add, check if
_isItemsCleared && Count == 2 && this is ShellItemCollection - Call
shell?.NotifyFlyoutBehaviorObservers()to trigger re-evaluation - Reset flag to
false
Why this is the best approach:
- Precise targeting: Only triggers in the exact clear+add scenario
- Minimal scope: Single file change (ShellElementCollection.cs)
- Clear intent: Boolean flag with obvious set/reset points
- No side effects: Doesn't affect other collection change scenarios
Alternatives considered:
6 other passing fixes were explored (override Add(), Shell.Initialize handler, SendFlyoutItemsChanged, etc.). All work, but the PR's approach is simplest and most targeted.
Platform Coverage
Tested platforms:
- ✅ Android (crash fix validated)
- ✅ Windows (icon visibility verified)
- ✅ iOS (icon visibility verified)
- ✅ Mac (snapshot committed)
UI tests:
- Test page:
Issue28078.cs- Reproduces clear+add scenario - Test:
ShellFlyoutMenuCrash- Verifies flyout opens after clear+add - Snapshots: Committed for all 4 platforms
PR Metadata Quality
Title: "Fixed FlyoutMenu icon issue when clearing and adding items"
- ✅ Describes the behavior fix
⚠️ Could be improved with platform prefix and component:Shell: Fix flyout crash/icon when clearing and adding items
Description:
- ✅ Clear issue detail for each platform
- ✅ Root cause documented
- ✅ Platforms tested listed
- ✅ Issue link included
- ✅ Before/after videos
- ❌ Missing required NOTE block at top (for users to test PR artifacts)
⚠️ "Description of change" is vague - could be more specific about the state tracking approach
Recommended additions to description:
- Add NOTE block at top (required):
<!-- 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!- Enhance "Description of change" to be more specific:
### Description of change
Added `_isItemsCleared` flag to `ShellElementCollection` to track when items are cleared. When adding items after a clear, the code now checks if exactly 2 items exist (the threshold for flyout visibility) and calls `NotifyFlyoutBehaviorObservers()` to force the platform handlers to recalculate flyout behavior and update the UI (show hamburger button, setup drawer layout, etc.).
**Key changes:**
- Set flag on `Clear()` (line 123)
- Check flag + Count==2 on item add (line 159)
- Call `shell?.NotifyFlyoutBehaviorObservers()` to trigger re-evaluation
- Reset flag after notificationCode Review Findings
✅ Implementation Quality:
- Clean, focused change with clear intent
- Well-commented (explains when flyout state should be updated)
- Appropriate null-safety (
shell?.) - Type-safe collection check (
this is ShellItemCollection)
- Variable naming (Copilot suggestion):
_isItemsClearedcould be clearer as_needsFlyoutBehaviorUpdate- but existing name is acceptable - Flag scope (Copilot concern): Flag is in base class but only checked for
ShellItemCollection- potential leak for other collection types. However, this is fine because:- Only
ShellItemCollectionchecks the flag - Flag is harmless for other collection types (set but never used)
- Keeps the logic in the base class where Clear() exists
- Only
No critical issues identified.
Recommendation Details
Approve because:
- Fix correctly resolves the crash and visibility issues
- Tests properly validate the fix (fail without, pass with)
- Implementation is clean and well-targeted
- Comprehensive platform coverage
- No alternative fixes found that are meaningfully simpler
Minor improvements for author (non-blocking):
- Add NOTE block to description (required for users testing PR builds)
- Consider more specific title:
Shell: Fix flyout crash/icon when clearing and adding items - Enhance "Description of change" with technical details
These are documentation improvements that don't affect the quality of the code fix itself.
📋 PR Finalization ReviewTitle:
|
| Scenario | Behavior | Risk |
|---|---|---|
| Add 3+ items after clear | Flag reset at Count == 2, subsequent adds don't retrigger | Low - Correct behavior |
| Clear without re-adding | Flag remains true until next Add | Low - No impact |
| Nested Clear/Add cycles | Flag resets properly on each cycle | Low - Each cycle independent |
| Single item → Single item | Count never reaches 2, no notification | Low - Expected (flyout stays disabled) |
Issues Fixed
Fixes #28078
Platforms Tested
- Android
- Windows
- iOS
- Mac
Screenshots
| Before Issue Fix | After Issue Fix |
|---|---|
28078BeforeFix.mov |
28078AfterFix.mov |
iOS:
| Before Issue Fix | After Issue Fix |
|---|---|
BeforeFix28078.mov |
AfterFix28078.mov |
Code Review: ⚠️ Issues Found
Code Review Findings for PR #28241
✅ Positive Observations
- Minimal, surgical fix - Only adds 10 lines to fix a cross-platform issue
- Good state management - Uses flag pattern to track clear/add cycles
- Correct threshold detection - Identifies the exact transition point (Count == 2) where flyout behavior changes
- Includes comprehensive tests - UI test with screenshot verification across all platforms
- Type safety - Properly checks
this is ShellItemCollectionbefore casting - Proper cleanup - Resets flag after notification to prevent duplicate calls
🟡 Suggestions
1. Consider Thread Safety
Current code:
bool _isItemsCleared;Observation: _isItemsCleared is accessed/modified in Clear() and InnerCollectionChanged() without synchronization.
Risk: Low - Shell operations are typically on UI thread, but if items are modified from multiple threads, race conditions possible.
Recommendation: Document that Shell item manipulation must occur on UI thread, or consider using volatile/Interlocked if thread safety is required.
2. Magic Number Documentation
Current code:
if (_isItemsCleared && Count == 2 && this is ShellItemCollection shellItemCollection)Observation: Count == 2 is a "magic number" without inline explanation.
Recommendation: Add inline comment explaining why 2 is the threshold:
// Count == 2 is the threshold where flyout transitions from Disabled (1 item) to Enabled (2+ items)
if (_isItemsCleared && Count == 2 && this is ShellItemCollection shellItemCollection)3. Null Safety Pattern
Current code:
var shell = shellItemCollection[0].Parent as Shell;
shell?.NotifyFlyoutBehaviorObservers();Observation: Assumes shellItemCollection[0] exists (Count == 2 guarantees this) and uses null-conditional operator for shell reference.
Recommendation: Consider adding defensive check or assertion:
if (shellItemCollection.Count < 1)
return; // Should never happen given Count == 2 check
var shell = shellItemCollection[0].Parent as Shell;
shell?.NotifyFlyoutBehaviorObservers();However: Given the Count == 2 check, current code is safe. This is more about defensive programming.
4. Edge Case: Rapid Clear/Add Cycles
Scenario: User calls Items.Clear() then adds 1 item, then calls Clear() again, then adds 2 items.
Current behavior:
- First Clear:
_isItemsCleared = true - Add 1 item: Flag stays true, Count == 1, no notification
- Second Clear:
_isItemsCleared = true(already true) - Add 2 items: Count == 2, notification triggered, flag reset
Observation: Handles correctly - flag is "sticky" until Count == 2 is reached.
Risk: None identified.
5. Platform Handler Initialization Timing
Observation: NotifyFlyoutBehaviorObservers() calls Handler?.UpdateValue() which requires platform handler to exist.
Question: What happens if items are replaced before handler is created?
From Shell.cs line 1972-1973:
if (CurrentItem == null || GetVisiblePage() == null)
return;Answer: Method guards against null CurrentItem/Page, so early returns safely. Handler?.UpdateValue() also uses null-conditional operator.
Verdict: Safely handled.
6. Test Coverage Gap: Count == 3+ Scenario
Current test (Issue28078.cs):
Items.Clear();
Items.Add(new _28708Page1());
Items.Add(new _28708Page2());Observation: Test only validates 0 → 2 items. Doesn't test 0 → 3+ items.
Recommendation: Consider adding test case:
Items.Clear();
Items.Add(new Page1());
Items.Add(new Page2());
Items.Add(new Page3());Risk: Low - Logic should handle Count >= 2 correctly (flag reset at Count == 2), but explicit test would verify.
7. Alternative: Use Count == 1 with Reset Delay
Alternative approach consideration:
Could the notification happen when Count transitions from 1 → 2, using previous count tracking?
int _previousCount;
void InnerCollectionChanged(...)
{
// ...
if (_previousCount == 1 && Count == 2 && this is ShellItemCollection shellItemCollection)
{
var shell = shellItemCollection[0].Parent as Shell;
shell?.NotifyFlyoutBehaviorObservers();
}
_previousCount = Count;
}Comparison:
- ✅ More general (catches any 1 → 2 transition, not just after Clear)
- ❌ More state to track
- ❌ Doesn't handle non-sequential adds (Insert at index 0, etc.)
Verdict: Current approach with _isItemsCleared flag is simpler and sufficient for the reported issue.
🔴 Critical Issues
None identified. The fix is sound and addresses the reported issue correctly.
Summary
The code change is well-implemented with a focused fix for the reported issue. The suggestions above are minor improvements for code clarity and defensive programming, but are not blockers. The current implementation correctly handles the state transition and platform notification timing.
Recommendation: ✅ Ready to merge after addressing title/description feedback. Code changes are solid.
PureWeen
left a comment
There was a problem hiding this comment.
@Vignesh-SF3580 can we use unit tests here instead of UITests?
5ef3efe to
0a16345
Compare
@PureWeen I’ve added a unit test to cover this scenario. |
|
/azp run maui-pr-uitests |
|
Azure Pipelines successfully started running 1 pipeline(s). |
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!
Issue Detail
Platform-specific symptoms:
IllegalArgumentException: No drawer view found with gravity LEFTwhen tapping flyout icon after items are replacedReproduction scenario:
Root Cause
When Shell items are dynamically replaced (cleared then re-added), the flyout behavior state is not properly updated on platform handlers.
Why this matters:
Items.Count == 1,GetEffectiveFlyoutBehavior()returnsFlyoutBehavior.Disabled(single-item shells don't need flyout)Items.Count >= 2, it should returnFlyoutBehavior.Flyout(multiple items require flyout navigation)The bug: When items are replaced dynamically, this state transition (disabled → enabled) was not triggering a notification to platform handlers, leaving them in stale state:
Description of Change
Added state tracking to
ShellElementCollectionto detect when items are cleared and then re-added, explicitly notifying flyout behavior observers when the flyout should transition from disabled to enabled.Implementation:
_isItemsClearedflag to track whenClear()is calledInnerCollectionChanged, when items are added after clearing:_isItemsCleared && Count == 2(the threshold where flyout should enable)shell.NotifyFlyoutBehaviorObservers()to update platform handlers_isItemsClearedflagWhy Count == 2 specifically?
This ensures platform handlers receive the flyout behavior update at exactly the moment when the flyout should become available.
Key Technical Details
NotifyFlyoutBehaviorObservers():OnFlyoutBehaviorChanged()on each observerIFlyoutView.FlyoutBehaviorType restriction:
this is ShellItemCollectionbecause onlyShellItemhasParentreference to ShellShellContentCollectionorShellSectionCollectionNormal update path:
Shell.AppearanceChanged()normally callsNotifyFlyoutBehaviorObservers()on structural changesWhat NOT to Do (for future agents)
Edge Cases
Issues Fixed
Fixes #28078
Platforms Tested
Screenshots
28078BeforeFix.mov
28078AfterFix.mov
iOS:
BeforeFix28078.mov
AfterFix28078.mov