diff --git a/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs b/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs index 3850a5f3aa7b..c5c8725ba264 100644 --- a/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs +++ b/src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs @@ -115,11 +115,19 @@ protected override void DisconnectHandler(FrameworkElement platformView) } if (_shellItem is IShellItemController shellItemController) + { shellItemController.ItemsCollectionChanged -= OnItemsChanged; - if (VirtualView.Parent is Shell shell) - { - shell.Navigated -= OnShellNavigated; + if (VirtualView.Parent is Shell shell) + { + shell.Navigated -= OnShellNavigated; + } + + foreach (var item in shellItemController.GetItems()) + { + item.PropertyChanged -= OnShellItemPropertyChanged; + } + } } @@ -203,6 +211,7 @@ internal void MapMenuItems() foreach (var item in shellItemController.GetItems()) { + item.PropertyChanged += OnShellItemPropertyChanged; if (Routing.IsImplicit(item)) items.Add(item.CurrentItem); else @@ -254,6 +263,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) @@ -409,6 +419,33 @@ void OnSearchBoxQuerySubmitted(Microsoft.UI.Xaml.Controls.AutoSuggestBox sender, } } + 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 a954d9dbfed7..602a7ed0ee00 100644 --- a/src/Controls/src/Core/Platform/Windows/TabbedPage/TabbedPageStyle.xaml +++ b/src/Controls/src/Core/Platform/Windows/TabbedPage/TabbedPageStyle.xaml @@ -7,6 +7,7 @@ x:Name="navViewItem" Content="{Binding Content}" Background="{Binding Background}" + IsEnabled="{Binding IsEnabled}" IsSelected="{Binding IsSelected, Mode=TwoWay}" MenuItemsSource="{Binding MenuItemsSource}" Icon="{Binding Icon}" diff --git a/src/Controls/src/Core/TabbedPage/TabbedPage.Windows.cs b/src/Controls/src/Core/TabbedPage/TabbedPage.Windows.cs index a079cbeea77a..49ee36888e2d 100644 --- a/src/Controls/src/Core/TabbedPage/TabbedPage.Windows.cs +++ b/src/Controls/src/Core/TabbedPage/TabbedPage.Windows.cs @@ -379,6 +379,7 @@ internal static void MapItemsSource(ITabbedViewHandler handler, TabbedPage view) vm.SelectedForeground = view.SelectedTabColor?.AsPaint()?.ToPlatform(); vm.UnselectedForeground = view.UnselectedTabColor?.AsPaint()?.ToPlatform(); vm.IsSelected = page == view.CurrentPage; + vm.IsEnabled = page.IsEnabled; }); handler.UpdateValue(nameof(TabbedPage.CurrentPage)); 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..a253e377a1bc --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue5161.cs @@ -0,0 +1,133 @@ +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!"); + } + } + } +} 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..215415d54055 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue5161.cs @@ -0,0 +1,28 @@ +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"); + } +} diff --git a/src/Core/src/Platform/Windows/NavigationViewItemViewModel.cs b/src/Core/src/Platform/Windows/NavigationViewItemViewModel.cs index aa0b0d9ba5c6..c1f4d3b045cc 100644 --- a/src/Core/src/Platform/Windows/NavigationViewItemViewModel.cs +++ b/src/Core/src/Platform/Windows/NavigationViewItemViewModel.cs @@ -82,6 +82,7 @@ internal class NavigationViewItemViewModel : INotifyPropertyChanged object? _content; bool _isSelected; + bool _isEnabled; WBrush? _selectedBackground; WBrush? _unselectedBackground; WBrush? _selectedForeground; @@ -232,6 +233,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));