Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ public override void ViewDidLoad()

UpdateSelectedIndex();
ShellSection.PropertyChanged += OnShellSectionPropertyChanged;
foreach (var shellContent in ShellSectionController.GetItems())
{
shellContent.PropertyChanged += OnShellContentPropertyChanged;
}
}

protected virtual Type GetCellType()
Expand All @@ -217,6 +221,10 @@ protected override void Dispose(bool disposing)
((IShellController)_shellContext.Shell).RemoveAppearanceObserver(this);
ShellSectionController.ItemsCollectionChanged -= OnShellSectionItemsChanged;
ShellSection.PropertyChanged -= OnShellSectionPropertyChanged;
foreach (var shellContent in ShellSectionController.GetItems())
{
shellContent.PropertyChanged -= OnShellContentPropertyChanged;
}

ShellSection = null;
_bar.RemoveFromSuperview();
Expand Down Expand Up @@ -279,9 +287,53 @@ protected virtual void UpdateSelectedIndex(bool animated = false)

void OnShellSectionItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
HandleEventsOnItemsChange(e);
ReloadData();
}

void HandleEventsOnItemsChange(NotifyCollectionChangedEventArgs e)
{
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;
}
}
}

void OnShellContentPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ShellContent.Title))
{
if (sender is ShellContent shellContent)
{
int index = ShellSectionController.GetItems().IndexOf(shellContent);
if (index >= 0)
{
UpdateHeaderTitle(index, shellContent);
}
}
}
}

void UpdateHeaderTitle(int index, ShellContent shellContent)
{
if (CollectionView.CellForItem(NSIndexPath.FromItemSection(index, 0)) is ShellSectionHeaderCell cell)
{
cell.Label.Text = shellContent.Title;
CollectionView.CollectionViewLayout.InvalidateLayout();
}
}

void ReloadData()
{
if (_isDisposed)
Expand Down
60 changes: 60 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue26049.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8" ?>
<Shell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue26049"
FlyoutBehavior="Disabled"
Title="Issue26049">
<TabBar AutomationId="TabBar">
<Tab Title="Nested Tabs" x:Name="tabs" AutomationId="tabbar">
<ShellContent x:Name="tab1" Title="Home">
<ContentPage>
<StackLayout HorizontalOptions="Center" Spacing="20">

<HorizontalStackLayout>
<Label Text="Current Shell Title: " FontAttributes="Bold"/>
<Label Text="{Binding Source={x:Reference tab1}, Path=Title}" AutomationId="FirstTabLabel"/>
</HorizontalStackLayout>

<HorizontalStackLayout>
<Label Text="New Tab Title: " FontAttributes="Bold"/>
<Label x:Name="newTabTitleLabel" AutomationId="NewTabTitleLabel"/>
</HorizontalStackLayout>

<HorizontalStackLayout>
<Label Text="Third Tab Title: " FontAttributes="Bold"/>
<Label x:Name="thirdTabTitleLabel" Text="{Binding Source={x:Reference tab3}, Path=Title}" AutomationId="ThirdTabTitleLabel"/>
</HorizontalStackLayout>

<Button Text="Change Title" AutomationId="ChangeShellContentTitle" VerticalOptions="Center" HorizontalOptions="Center" WidthRequest="150" HeightRequest="40" Clicked="OnButtonClicked"/>

<Button Text="Add New Tab" AutomationId="AddShellContent"
Clicked="OnAddShellContentClicked"/>

<Button Text="Update New Tab Title" AutomationId="UpdateNewShellContentTitle"
Clicked="OnUpdateNewShellContentTitleClicked"/>

<Button Text="Remove New Tab" AutomationId="RemoveShellContent"
Clicked="OnRemoveShellContentClicked"/>

<Button Text="Update Third Tab Title" AutomationId="UpdateThirdTabTitle"
Clicked="OnUpdateThirdTabTitleClicked"/>

</StackLayout>
</ContentPage>
</ShellContent>

<ShellContent x:Name="tab2" Title="Settings">
<ContentPage>
<Label Text="This is Settings page"/>
</ContentPage>
</ShellContent>

<ShellContent x:Name="tab3" Title="Profile">
<ContentPage>
<Label Text="This is Profile page"/>
</ContentPage>
</ShellContent>
</Tab>
</TabBar>

</Shell>
65 changes: 65 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue26049.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 26049, "[iOS] Fix ShellContent Title Does Not Update at Runtime", PlatformAffected.iOS | PlatformAffected.macOS)]
public partial class Issue26049 : Shell
{
ShellContent _dynamicShellContent;

public Issue26049()
{
InitializeComponent();
}

void OnButtonClicked(object sender, EventArgs e)
{
this.tab1.Title = "Updated";
}

void OnAddShellContentClicked(object sender, EventArgs e)
{
if (_dynamicShellContent == null)
{
_dynamicShellContent = new ShellContent
{
Title = "New Tab",
Content = new ContentPage
{
Content = new Label { Text = "This is a dynamically added tab." }
}
};

this.tabs.Items.Add(_dynamicShellContent);
UpdateNewTabTitleLabel();
}
}

void OnUpdateNewShellContentTitleClicked(object sender, EventArgs e)
{
if (_dynamicShellContent != null)
{
_dynamicShellContent.Title = "Updated Title";
UpdateNewTabTitleLabel();
}
}

void OnRemoveShellContentClicked(object sender, EventArgs e)
{
if (_dynamicShellContent != null)
{
this.tabs.Items.Remove(_dynamicShellContent);
_dynamicShellContent = null;
newTabTitleLabel.Text = "";
}
}

void OnUpdateThirdTabTitleClicked(object sender, EventArgs e)
{
this.tab3.Title = "Updated Profile";
thirdTabTitleLabel.Text = this.tab3.Title;
}

void UpdateNewTabTitleLabel()
{
newTabTitleLabel.Text = _dynamicShellContent?.Title;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#if TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_WINDOWS //More information - https://github.com/dotnet/maui/issues/27494
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue26049 : _IssuesUITest
{
public Issue26049(TestDevice device) : base(device)
{
}

public override string Issue => "[iOS] Fix ShellContent Title Does Not Update at Runtime";

[Test, Order(1)]
[Category(UITestCategories.Shell)]
public void VerifyFirstShellContentTitle()
{
App.WaitForElement("ChangeShellContentTitle");
App.Click("ChangeShellContentTitle");
VerifyScreenshot();
}

[Test, Order(2)]
[Category(UITestCategories.Shell)]
public void VerifyNewlyAddedShellContentTitle()
{
App.WaitForElement("AddShellContent");
App.Click("AddShellContent");
App.Click("UpdateNewShellContentTitle");
VerifyScreenshot();
}

[Test, Order(3)]
[Category(UITestCategories.Shell)]
public void VerifyExistingTabTitle()
{
App.WaitForElement("RemoveShellContent");
App.Click("RemoveShellContent");
App.Click("UpdateThirdTabTitle");
VerifyScreenshot();
}
}
}
#endif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading