From bf65c0193e83e2fbaa24d30f6ca67cf9c5ed9586 Mon Sep 17 00:00:00 2001 From: devanathan-vaithiyanathan <114395405+devanathan-vaithiyanathan@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:12:39 +0530 Subject: [PATCH 1/4] Update ShellSectionHandler.Windows.cs --- .../Shell/ShellSectionHandler.Windows.cs | 81 +++++++++++++++---- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs b/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs index c215ea12c12a..7b45cbddc9b6 100644 --- a/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs +++ b/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs @@ -53,11 +53,15 @@ public override void SetVirtualView(Maui.IElement view) { if (_shellSection != null) { - ((IShellSectionController)_shellSection).RemoveDisplayedPageObserver(this); ((IShellSectionController)_shellSection).NavigationRequested -= OnNavigationRequested; ((IShellSectionController)_shellSection).ItemsCollectionChanged -= OnItemsCollectionChanged; + foreach (var item in ((IShellSectionController)_shellSection).GetItems()) + { + item.PropertyChanged -= OnShellContentPropertyChanged; + } + if (_lastShell?.Target is IShellController shell) { shell.RemoveAppearanceObserver(this); @@ -87,39 +91,60 @@ public override void SetVirtualView(Maui.IElement view) ((IShellSectionController)_shellSection).NavigationRequested += OnNavigationRequested; ((IShellSectionController)_shellSection).ItemsCollectionChanged += OnItemsCollectionChanged; + foreach (var item in ((IShellSectionController)_shellSection).GetItems()) + { + item.PropertyChanged += OnShellContentPropertyChanged; + } + var shell = _shellSection.FindParentOfType() as IShellController; if (shell != null) { _lastShell = new WeakReference(shell); shell.AddAppearanceObserver(this, _shellSection); } - - // AddDisplayedPageObserver immediately invokes the callback with the current page, - // but at that point PendingNavigationTask is already set from MapCurrentItem - // (which runs via base.SetVirtualView above), so it is safely skipped. - ((IShellSectionController)_shellSection).AddDisplayedPageObserver(this, OnDisplayedPageChanged); } } - // Called when ShellSection.DisplayedPage changes — covers both content changes and - // navigation pushes. We only act on content changes (stack depth == 1, no pending nav). - void OnDisplayedPageChanged(Page page) + // Called when ShellContent.Content changes on a specific tab — forces Windows to + // rebuild the navigation stack so the new page becomes visible. + // Using PropertyChanged on each ShellContent (rather than AddDisplayedPageObserver) + // avoids false triggers during tab switches: OnCurrentItemChanged (the BindableProperty + // propertyChanged callback) fires BEFORE the handler's MapCurrentItem (which fires via + // the PropertyChanged event), so PendingNavigationTask is not yet set when + // DisplayedPage changes during a tab switch. + void OnShellContentPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) { if (VirtualView is null) + { + return; + } + + if (e.PropertyName != ShellContent.ContentProperty.PropertyName) + { + return; + } + + if (sender is not ShellContent shellContent) + { return; + } + + // Only sync when the changed content belongs to the active tab at root level. + if (shellContent != VirtualView.CurrentItem) + { + return; + } - // Push/pop navigation is handled by OnNavigationRequested; skip those cases. if (VirtualView.Stack.Count > 1) + { return; + } - // Tab switches are handled by MapCurrentItem which sets PendingNavigationTask first - // (because the property mapper fires before the propertyChanged callback that calls - // UpdateDisplayedPage). Skip when another navigation is already in flight. if (VirtualView.PendingNavigationTask != null) + { return; + } - // ContentCache has been updated by OnContentChanged at this point, so - // SyncNavigationStack will correctly pick up the new page via GetOrCreateContent(). SyncNavigationStack(false, null); } @@ -133,6 +158,23 @@ void OnItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e if (_shellSection is null) return; + if (e.OldItems != null) + { + foreach (ShellContent item in e.OldItems) + { + item.PropertyChanged -= OnShellContentPropertyChanged; + } + } + + + if (e.NewItems != null) + { + foreach (ShellContent item in e.NewItems) + { + item.PropertyChanged += OnShellContentPropertyChanged; + } + } + if (_shellSection.Parent is ShellItem shellItem && shellItem.Handler is ShellItemHandler shellItemHandler) { shellItemHandler.MapMenuItems(); @@ -187,8 +229,13 @@ protected override void ConnectHandler(WFrame platformView) protected override void DisconnectHandler(WFrame platformView) { if (_shellSection != null) - ((IShellSectionController)_shellSection).RemoveDisplayedPageObserver(this); - + { + foreach (var item in ((IShellSectionController)_shellSection).GetItems()) + { + item.PropertyChanged -= OnShellContentPropertyChanged; + } + } + _navigationManager?.Disconnect(VirtualView, platformView); base.DisconnectHandler(platformView); } From f7831f665a86fc1a9f084b9663b0354f1cefd4c2 Mon Sep 17 00:00:00 2001 From: devanathan-vaithiyanathan <114395405+devanathan-vaithiyanathan@users.noreply.github.com> Date: Thu, 11 Jun 2026 16:13:11 +0530 Subject: [PATCH 2/4] Update ShellSectionHandler.Windows.cs --- .../Shell/ShellSectionHandler.Windows.cs | 50 +++++++++++++++---- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs b/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs index 7b45cbddc9b6..efc5a350651c 100644 --- a/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs +++ b/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs @@ -26,6 +26,7 @@ public partial class ShellSectionHandler : ElementHandler, StackNavigationManager? _navigationManager; WeakReference? _lastShell; + List? _subscribedItems; public ShellSectionHandler() : base(Mapper, CommandMapper) { @@ -67,6 +68,7 @@ public override void SetVirtualView(Maui.IElement view) shell.RemoveAppearanceObserver(this); } _lastShell = null; + _subscribedItems?.Clear(); } // If we've already connected to the navigation manager @@ -88,12 +90,16 @@ public override void SetVirtualView(Maui.IElement view) _shellSection = (ShellSection)view; if (_shellSection != null) { + _subscribedItems ??= new HashSet(); + _subscribedItems.Clear(); + ((IShellSectionController)_shellSection).NavigationRequested += OnNavigationRequested; ((IShellSectionController)_shellSection).ItemsCollectionChanged += OnItemsCollectionChanged; foreach (var item in ((IShellSectionController)_shellSection).GetItems()) { item.PropertyChanged += OnShellContentPropertyChanged; + _subscribedItems.Add(item); } var shell = _shellSection.FindParentOfType() as IShellController; @@ -155,26 +161,51 @@ void OnNavigationRequested(object? sender, NavigationRequestedEventArgs e) void OnItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { - if (_shellSection is null) + if (_shellSection is null || _subscribedItems is null) + { return; + } - if (e.OldItems != null) + // Handle Reset action - collection has been completely cleared and refilled + if (e.Action == NotifyCollectionChangedAction.Reset) { - foreach (ShellContent item in e.OldItems) + // Unsubscribe from all previously subscribed items + foreach (var item in _subscribedItems) { item.PropertyChanged -= OnShellContentPropertyChanged; } - } - + _subscribedItems.Clear(); - if (e.NewItems != null) - { - foreach (ShellContent item in e.NewItems) + // Subscribe to all items currently in the section + foreach (var item in ((IShellSectionController)_shellSection).GetItems()) { item.PropertyChanged += OnShellContentPropertyChanged; + _subscribedItems.Add(item); } } - + else + { + // Handle Remove action + if (e.OldItems != null) + { + foreach (ShellContent item in e.OldItems) + { + item.PropertyChanged -= OnShellContentPropertyChanged; + _subscribedItems.Remove(item); + } + } + + // Handle Add action + if (e.NewItems != null) + { + foreach (ShellContent item in e.NewItems) + { + item.PropertyChanged += OnShellContentPropertyChanged; + _subscribedItems.Add(item); + } + } + } + if (_shellSection.Parent is ShellItem shellItem && shellItem.Handler is ShellItemHandler shellItemHandler) { shellItemHandler.MapMenuItems(); @@ -234,6 +265,7 @@ protected override void DisconnectHandler(WFrame platformView) { item.PropertyChanged -= OnShellContentPropertyChanged; } + _subscribedItems?.Clear(); } _navigationManager?.Disconnect(VirtualView, platformView); From ab6cbadf53242d64bc005602e2d5a07d20c8b82f Mon Sep 17 00:00:00 2001 From: devanathan-vaithiyanathan <114395405+devanathan-vaithiyanathan@users.noreply.github.com> Date: Fri, 12 Jun 2026 13:46:47 +0530 Subject: [PATCH 3/4] Update ShellSectionHandler.Windows.cs --- .../src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs b/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs index efc5a350651c..32f127a7ca19 100644 --- a/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs +++ b/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs @@ -90,7 +90,7 @@ public override void SetVirtualView(Maui.IElement view) _shellSection = (ShellSection)view; if (_shellSection != null) { - _subscribedItems ??= new HashSet(); + _subscribedItems ??= new List(); _subscribedItems.Clear(); ((IShellSectionController)_shellSection).NavigationRequested += OnNavigationRequested; From 76f0b6f5bdffdc1a2e348e6c82b2226a2355b8e0 Mon Sep 17 00:00:00 2001 From: devanathan-vaithiyanathan <114395405+devanathan-vaithiyanathan@users.noreply.github.com> Date: Fri, 12 Jun 2026 13:52:00 +0530 Subject: [PATCH 4/4] Update ShellSectionHandler.Windows.cs --- .../Core/Handlers/Shell/ShellSectionHandler.Windows.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs b/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs index 32f127a7ca19..17ec54c936b0 100644 --- a/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs +++ b/src/Controls/src/Core/Handlers/Shell/ShellSectionHandler.Windows.cs @@ -58,9 +58,13 @@ public override void SetVirtualView(Maui.IElement view) ((IShellSectionController)_shellSection).ItemsCollectionChanged -= OnItemsCollectionChanged; - foreach (var item in ((IShellSectionController)_shellSection).GetItems()) + if (_subscribedItems != null) { - item.PropertyChanged -= OnShellContentPropertyChanged; + foreach (var item in _subscribedItems) + { + item.PropertyChanged -= OnShellContentPropertyChanged; + } + _subscribedItems.Clear(); } if (_lastShell?.Target is IShellController shell) @@ -68,7 +72,6 @@ public override void SetVirtualView(Maui.IElement view) shell.RemoveAppearanceObserver(this); } _lastShell = null; - _subscribedItems?.Clear(); } // If we've already connected to the navigation manager