diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs index d969e5691f27..8eee04ab2818 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs @@ -295,7 +295,13 @@ protected override void OnDisplayedPageChanged(Page newPage, Page oldPage) oldPage.PropertyChanged -= OnDisplayedElementPropertyChanged; if (newPage is not null) + { newPage.PropertyChanged += OnDisplayedElementPropertyChanged; + if (oldPage is null) + { + _menuSetup = false; + } + } if (newPage is not null && !_menuSetup) { diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellItemRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellItemRenderer.cs index 48bc62a05ec2..6c8466287185 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellItemRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellItemRenderer.cs @@ -358,7 +358,11 @@ void GoTo(ShellSection shellSection) if (shellSection == null || _currentSection == shellSection) return; var renderer = RendererForShellContent(shellSection); - if (renderer?.ViewController != SelectedViewController) + + if (renderer is null) + return; + + if (renderer.ViewController != SelectedViewController) SelectedViewController = renderer.ViewController; CurrentRenderer = renderer; diff --git a/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs b/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs index b60e49ca4126..96121f5e6373 100644 --- a/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs +++ b/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs @@ -432,7 +432,7 @@ void OnCurrentShellSectionPropertyChanged(object? sender, System.ComponentModel. if (_mainLevelTabs == null) return; - var currentItem = VirtualView.CurrentItem.CurrentItem; + var currentItem = VirtualView.CurrentItem?.CurrentItem; NavigationViewItemViewModel? navigationViewItemViewModel = null; foreach (var item in _mainLevelTabs) diff --git a/src/Controls/src/Core/Shell/ShellItem.cs b/src/Controls/src/Core/Shell/ShellItem.cs index 75f5802cd0b3..06d38d5c4641 100644 --- a/src/Controls/src/Core/Shell/ShellItem.cs +++ b/src/Controls/src/Core/Shell/ShellItem.cs @@ -271,7 +271,7 @@ void OnVisibleChildRemoved(Element child) if (CurrentItem == child) { if (ShellItemController.GetItems().Count == 0) - ClearValue(CurrentItemProperty, specificity: SetterSpecificity.FromHandler); + ClearValue(CurrentItemProperty); else SetValueFromRenderer(CurrentItemProperty, ShellItemController.GetItems()[0]); } diff --git a/src/Controls/src/Core/Shell/ShellSection.cs b/src/Controls/src/Core/Shell/ShellSection.cs index e5b62bc83075..9bdee2880517 100644 --- a/src/Controls/src/Core/Shell/ShellSection.cs +++ b/src/Controls/src/Core/Shell/ShellSection.cs @@ -707,7 +707,7 @@ void OnVisibleChildRemoved(Element child) var contentItems = ShellSectionController.GetItems(); if (contentItems.Count == 0) { - ClearValue(CurrentItemProperty, specificity: SetterSpecificity.FromHandler); + ClearValue(CurrentItemProperty); } else { diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ShellTabItemsShouldUpdateForDynamicChangesInVisibility.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ShellTabItemsShouldUpdateForDynamicChangesInVisibility.png new file mode 100644 index 000000000000..55251cdceb7c Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ShellTabItemsShouldUpdateForDynamicChangesInVisibility.png differ diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue8788.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue8788.xaml new file mode 100644 index 000000000000..66b5216d53d6 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue8788.xaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue8788.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue8788.xaml.cs new file mode 100644 index 000000000000..1fbdaba01440 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue8788.xaml.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Maui.Controls.Sample.Issues +{ + [XamlCompilation(XamlCompilationOptions.Compile)] + [Issue(IssueTracker.Github, 8788, "Shell Tab is still visible after set Tab.IsVisible to false", PlatformAffected.Android)] + public partial class Issue8788 : Shell + { + public Issue8788() + { + InitializeComponent(); + } + + private void MenuItem_Clicked(object sender, EventArgs e) + { +#if ANDROID + Tab2.IsVisible = true; + Tab3.IsVisible = true; + Tab1.IsVisible = false; +#else + Tab1.IsVisible = false; + Tab2.IsVisible = true; + Tab3.IsVisible = true; +#endif + } + } + + public partial class MainTabPage : ContentPage + { + public MainTabPage() + { + Content = new VerticalStackLayout() + { + new Label(){ + Text = "Page Loaded in first Tab", + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center, + TextDecorations = TextDecorations.Underline, + + }, + }; + } + } + + public partial class SecondTabPage : ContentPage + { + public SecondTabPage() + { + Content = new VerticalStackLayout() + { + new Label(){ + Text = "Page Loaded in Second Tab", + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center, + TextDecorations = TextDecorations.Underline, + + }, + }; + } + } + public partial class ThirdTabPage : ContentPage + { + public ThirdTabPage() + { + Content = new VerticalStackLayout() + { + new Label(){ + Text = "Page Loaded in Third Tab", + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center, + TextDecorations = TextDecorations.Underline, + + }, + }; + } + } +} diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue8788.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue8788.cs new file mode 100644 index 000000000000..95f2875306f6 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue8788.cs @@ -0,0 +1,28 @@ +#if !MACCATALYST +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues +{ + internal class Issue8788 : _IssuesUITest + { + public Issue8788(TestDevice device) : base(device) { } + + public override string Issue => "Shell Tab is still visible after set Tab.IsVisible to false"; + + [Test] + [Category(UITestCategories.Shell)] + public void ShellTabItemsShouldUpdateForDynamicChangesInVisibility() + { +#if WINDOWS + App.TapCoordinates(100, 57); +#else + App.WaitForElement("FirstButton"); + App.Tap("FirstButton"); +#endif + VerifyScreenshot(); + } + } +} +#endif \ No newline at end of file diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShellTabItemsShouldUpdateForDynamicChangesInVisibility.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShellTabItemsShouldUpdateForDynamicChangesInVisibility.png new file mode 100644 index 000000000000..19817a5c81c7 Binary files /dev/null and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShellTabItemsShouldUpdateForDynamicChangesInVisibility.png differ diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ShellTabItemsShouldUpdateForDynamicChangesInVisibility.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ShellTabItemsShouldUpdateForDynamicChangesInVisibility.png new file mode 100644 index 000000000000..215b266fc069 Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ShellTabItemsShouldUpdateForDynamicChangesInVisibility.png differ