diff --git a/src/Controls/src/Core/ShellToolbar.cs b/src/Controls/src/Core/ShellToolbar.cs index d74cbf82a16d..d6c324268168 100644 --- a/src/Controls/src/Core/ShellToolbar.cs +++ b/src/Controls/src/Core/ShellToolbar.cs @@ -169,27 +169,47 @@ internal void UpdateTitle() Shell.TitleViewProperty, Shell.GetTitleView(_shell)); + var title = GetCurrentTitle(); + if (!IsShellTitleSetByUser()) + _shell.SetValueFromRenderer(Shell.TitleProperty, title); + if (TitleView != null) { Title = String.Empty; return; } + Title = title; + } + + string GetCurrentTitle() + { Page? currentPage = _shell.GetCurrentShellPage(); if (currentPage?.IsSet(Page.TitleProperty) == true) { - Title = currentPage.Title ?? String.Empty; + return currentPage.Title ?? String.Empty; } // We only want to use the ShellContent as a title if no pages have been // Pushed onto the stack else if (_shell.Navigation?.NavigationStack?.Count <= 1) { - Title = _shell.CurrentContent?.Title ?? String.Empty; - } - else - { - Title = String.Empty; + return _shell.CurrentContent?.Title ?? String.Empty; } + + return String.Empty; + } + + bool IsShellTitleSetByUser() + { + var titleContext = _shell.GetContext(Shell.TitleProperty); + if (titleContext == null) + return false; + + if (titleContext.Bindings.Count > 0) + return true; + + var specificity = titleContext.Values.GetSpecificity(); + return specificity != SetterSpecificity.DefaultValue && specificity != SetterSpecificity.FromHandler; } } } diff --git a/src/Controls/tests/Core.UnitTests/ShellToolbarTests.cs b/src/Controls/tests/Core.UnitTests/ShellToolbarTests.cs index d18d47cb440a..ef4fa4829bcf 100644 --- a/src/Controls/tests/Core.UnitTests/ShellToolbarTests.cs +++ b/src/Controls/tests/Core.UnitTests/ShellToolbarTests.cs @@ -270,6 +270,64 @@ public async Task TitleAndTitleViewAreMutuallyExclusive() Assert.Equal("Test Title", toolbar.Title); } + [Fact] + public void ShellTitleReflectsCurrentPageTitleForTitleViewBindings() + { + var contentPage = new ContentPage() { Title = "Test Title" }; + var label = new Label(); + var titleView = new VerticalStackLayout() + { + Children = + { + label + } + }; + + TestShell testShell = new TestShell(contentPage); + _ = new Window() + { + Page = testShell + }; + + label.SetBinding(Label.TextProperty, new Binding(nameof(Shell.Title), source: testShell)); + Shell.SetTitleView(contentPage, titleView); + + Assert.Empty(testShell.Toolbar.Title); + Assert.Equal("Test Title", testShell.Title); + Assert.Equal("Test Title", label.Text); + + contentPage.Title = "Updated Test Title"; + + Assert.Equal("Updated Test Title", testShell.Title); + Assert.Equal("Updated Test Title", label.Text); + } + + [Fact] + public void ShellTitleBindingIsNotOverwrittenByCurrentPageTitle() + { + var contentPage = new ContentPage() { Title = "Page Title" }; + var titleView = new VerticalStackLayout(); + var viewModel = new TestShellViewModel() { Text = "App Title" }; + + TestShell testShell = new TestShell(contentPage); + _ = new Window() + { + Page = testShell + }; + + testShell.SetBinding(Shell.TitleProperty, new Binding(nameof(TestShellViewModel.Text), BindingMode.TwoWay, source: viewModel)); + Shell.SetTitleView(contentPage, titleView); + + Assert.Empty(testShell.Toolbar.Title); + Assert.Equal("App Title", testShell.Title); + Assert.Equal("App Title", viewModel.Text); + + contentPage.Title = "Updated Page Title"; + + Assert.Equal("App Title", testShell.Title); + Assert.Equal("App Title", viewModel.Text); + } + [Fact] public void ContentPageColorsPropagateToShellToolbar() {