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 ff509574fd5f..a55fef2044e9 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellItemRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellItemRenderer.cs @@ -308,9 +308,20 @@ void CreateTabRenderers() // Make sure we are at the right item GoTo(ShellItem.CurrentItem); + UpdateCellsEnabled(); UpdateMoreCellsEnabled(); } + private void UpdateCellsEnabled() + { + for (int i = 1; i < TabBar.Items.Length; i++) + { + var tab = TabBar.Items[i]; + var itemRenderer = RendererForViewController(ViewControllers[i]); + tab.Enabled = itemRenderer.ShellSection.IsEnabled; + } + } + void UpdateMoreCellsEnabled() { var moreNavigationCells = GetMoreNavigationCells(); diff --git a/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs b/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs index c1f0c2f021ce..8d619079a2d9 100644 --- a/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs +++ b/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs @@ -100,7 +100,13 @@ protected override void DisconnectHandler(FrameworkElement platformView) } if (_shellItem is IShellItemController shellItemController) + { shellItemController.ItemsCollectionChanged -= OnItemsChanged; + foreach (var item in shellItemController.GetItems()) + { + item.PropertyChanged -= OnShellItemPropertyChanged; + } + } } public override void SetVirtualView(Maui.IElement view) @@ -158,6 +164,7 @@ internal void MapMenuItems() foreach (var item in shellItemController.GetItems()) { + item.PropertyChanged += OnShellItemPropertyChanged; if (Routing.IsImplicit(item)) items.Add(item.CurrentItem); else @@ -209,6 +216,7 @@ internal void MapMenuItems() void SetValues(BaseShellItem bsi, NavigationViewItemViewModel vm) { vm.Content = bsi.Title; + vm.IsEnabled = bsi.IsEnabled; var iconSource = bsi.Icon?.ToIconSource(MauiContext!); if (iconSource != null) @@ -345,6 +353,27 @@ void OnSearchBoxQuerySubmitted(Microsoft.UI.Xaml.Controls.AutoSuggestBox sender, null, null, null, MauiContext); } + private void OnShellItemPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (_mainLevelTabs == null || sender is not BaseShellItem shellItem) + return; + for (int i = 0; i < _mainLevelTabs.Count; i++) + { + if (_mainLevelTabs[i].Data != sender) + continue; + switch (e.PropertyName) + { + case nameof(BaseShellItem.IsEnabled): + _mainLevelTabs[i].IsEnabled = shellItem.IsEnabled; + break; + case nameof(BaseShellItem.Title): + _mainLevelTabs[i].Content = shellItem.Title; + break; + } + return; + } + } + void OnCurrentSearchHandlerPropertyChanged(object? sender, PropertyChangedEventArgs e) { if (_currentSearchHandler is null) diff --git a/src/Controls/src/Core/Platform/Windows/TabbedPage/TabbedPageStyle.xaml b/src/Controls/src/Core/Platform/Windows/TabbedPage/TabbedPageStyle.xaml index 1756541e112e..376583321340 100644 --- a/src/Controls/src/Core/Platform/Windows/TabbedPage/TabbedPageStyle.xaml +++ b/src/Controls/src/Core/Platform/Windows/TabbedPage/TabbedPageStyle.xaml @@ -8,6 +8,7 @@ Content="{Binding Content}" Foreground="{Binding TitleColor}" Background="{Binding Background}" + IsEnabled="{Binding IsEnabled}" IsSelected="{Binding IsSelected, Mode=TwoWay}" MenuItemsSource="{Binding MenuItemsSource}" Icon="{Binding Icon}" diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue5161.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue5161.cs new file mode 100644 index 000000000000..77625568fbeb --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue5161.cs @@ -0,0 +1,132 @@ +using System; +using Microsoft.Maui.Controls; + +namespace Maui.Controls.Sample.Issues; +[Issue(IssueTracker.Github, 5161, "ShellContent IsEnabledProperty does not work", PlatformAffected.iOS)] +public class Issue5161 : Shell +{ + public Issue5161() + { + var mainPageTab = new Tab + { + Title = "FirstPage", + IsEnabled = true, + }; + mainPageTab.Items.Add(new ShellContent + { + ContentTemplate = new DataTemplate(() => new Issue5161_MainPage()) + }); + + var secondPageTab = new Tab + { + Title = "SecondTab", + IsEnabled = false, + AutomationId = "SecondTab" + }; + secondPageTab.Items.Add(new ShellContent + { + ContentTemplate = new DataTemplate(() => new SecondPage()) + }); + var thirdTab = new Tab + { + Title = "ThirdTab", + IsEnabled = true, + AutomationId = "ThirdTab" + }; + thirdTab.Items.Add(new ShellContent + { + ContentTemplate = new DataTemplate(() => new ThirdPage()) + }); + var tabBar = new TabBar(); + tabBar.Items.Add(mainPageTab); + tabBar.Items.Add(secondPageTab); + tabBar.Items.Add(thirdTab); + Items.Add(tabBar); + } + + public class Issue5161_MainPage : ContentPage + { + public Issue5161_MainPage() + { + Content = new StackLayout + { + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center, + Children = + { + new Label + { + Text = "This is First Page", + } + } + }; + } + } + + public class SecondPage : ContentPage + { + public SecondPage() + { + Content = new StackLayout + { + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center, + Children = + { + new Label + { + Text="This is second Page", + AutomationId="SecondPageLabel" + } + } + }; + } + } + public class ThirdPage : ContentPage + { + public ThirdPage() + { + var label = new Label + { + Text = "This is Third Page", + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + AutomationId = "ThirdPageLabel" + }; + + var button = new Button + { + Text = "Enable SecondTab", + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + AutomationId = "EnableSecondTab" + }; + button.Clicked += OnButtonClicked; + Content = new StackLayout + { + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center, + Children = + { + label, + button + } + }; + + } + private void OnButtonClicked(object sender, EventArgs e) + { + if (Application.Current?.Windows.Count > 0 && + Application.Current.Windows[0].Page is Shell shell) + { + var secondTab = shell.CurrentItem?.Items[1]; + if (secondTab is not null) + secondTab.IsEnabled = true; + } + else + { + System.Diagnostics.Debug.WriteLine("Shell not found!"); + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue5161.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue5161.cs new file mode 100644 index 000000000000..1e817bded70c --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue5161.cs @@ -0,0 +1,27 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; +public class Issue5161 : _IssuesUITest +{ + public Issue5161(TestDevice testDevice) : base(testDevice) + { + } + + public override string Issue => "ShellContent IsEnabledProperty does not work"; + + [Test] + [Category(UITestCategories.Shell)] + public void CheckIsEnabled() + { + App.WaitForElement("ThirdTab"); + App.Tap("ThirdTab"); + App.WaitForElement("ThirdPageLabel"); + App.Tap("SecondTab"); + App.WaitForNoElement("SecondPageLabel"); + App.Tap("EnableSecondTab"); + App.Tap("SecondTab"); + App.WaitForElement("SecondPageLabel"); + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/NavigationViewItemViewModel.cs b/src/Core/src/Platform/Windows/NavigationViewItemViewModel.cs index 515f6c310479..0dcecd517458 100644 --- a/src/Core/src/Platform/Windows/NavigationViewItemViewModel.cs +++ b/src/Core/src/Platform/Windows/NavigationViewItemViewModel.cs @@ -81,6 +81,7 @@ internal class NavigationViewItemViewModel : INotifyPropertyChanged object? _content; bool _isSelected; + bool _isEnabled; WBrush? _selectedBackground; WBrush? _unselectedBackground; WBrush? _selectedForeground; @@ -218,6 +219,18 @@ public bool IsSelected } } + public bool IsEnabled + { + get => _isEnabled; + set + { + if (_isEnabled != value) + { + _isEnabled = value; + OnPropertyChanged(nameof(IsEnabled)); + } + } + } void OnPropertyChanged(string args) => OnPropertyChanged(new PropertyChangedEventArgs(args));