Skip to content

Fix Shell.Title binding in TitleView - #35800

Merged
kubaflo merged 2 commits into
inflight/currentfrom
jfversluis/fix-shell-title-binding
Jun 12, 2026
Merged

Fix Shell.Title binding in TitleView#35800
kubaflo merged 2 commits into
inflight/currentfrom
jfversluis/fix-shell-title-binding

Conversation

@jfversluis

Copy link
Copy Markdown
Member

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description of Change

Shell.TitleView content can bind to the Shell instance, but Shell.Title was not updated from the active page title. This meant bindings such as {Binding Title, Source={x:Reference Shell}} resolved to null even when the current ContentPage.Title was set.

This change mirrors the effective current page or ShellContent title into Shell.Title when Shell does not already have a user-set title. The rendered toolbar title still remains empty while a custom TitleView is active, and explicit Shell titles continue to work for Window title fallback.

A core unit test covers the TitleView binding scenario and verifies updates when the current page title changes.

Issues Fixed

Fixes #35761

Synchronize the effective Shell page title to Shell.Title so TitleView bindings can resolve the current page title without duplicating the rendered toolbar title.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35800

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35800"

@kubaflo

kubaflo commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 1 findings

See inline comments for details.


var title = GetCurrentTitle();
if (!IsShellTitleSetByUser())
_shell.SetValueFromRenderer(Shell.TitleProperty, title);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[major] Logic and Correctness — This still treats an explicit TwoWay binding on Shell.Title as handler-owned state and overwrites it with the current page title. BindableObject.SetBinding stores TwoWay bindings with SetterSpecificity.FromHandler, so IsShellTitleSetByUser() returns false for <Shell Title="{Binding AppTitle, Mode=TwoWay}">; when a TitleView is applied or the page title changes, this line pushes the page title into Shell.Title and back into the view model instead of preserving the app's binding. Please distinguish an actual binding in the property context from renderer-generated title values before calling SetValueFromRenderer.

@MauiBot MauiBot added s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Jun 8, 2026
MauiBot

This comment was marked as outdated.

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please check the ai's suggestions?

@kubaflo

kubaflo commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

/review

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jun 10, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 1 findings

See inline comments for details.

return false;

var specificity = titleContext.Values.GetSpecificity();
return specificity != SetterSpecificity.DefaultValue && specificity != SetterSpecificity.FromHandler;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[major] Navigation & Shell — This treats SetterSpecificity.FromHandler as toolbar-owned, but explicit TwoWay bindings on Shell.Title are also registered with FromHandler (BindableObject.SetBinding). When a user binds Shell.Title TwoWay and a TitleView is active, UpdateTitle() can overwrite the bound view-model value with the current page title. Please treat an existing binding on Shell.TitleProperty as user intent before falling back to the specificity check.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you fix it?

MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 10, 2026

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you apply the ai's suggestions please?

@kubaflo

This comment was marked as outdated.

@github-actions github-actions Bot added the s/agent-ready-for-rerun AI review has a new PR-author comment or commit and is ready for rerun label Jun 10, 2026
Treat existing Shell.Title bindings as user-owned state before synchronizing the current page title for TitleView bindings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kubaflo

kubaflo commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer -p android

@github-actions github-actions Bot added s/agent-review-in-progress AI review is currently running for this PR and removed s/agent-ready-for-rerun AI review has a new PR-author comment or commit and is ready for rerun labels Jun 11, 2026
@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 11, 2026
@kubaflo

kubaflo commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer -p android

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jun 11, 2026
@MauiBot MauiBot added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-fix-win AI found a better alternative fix than the PR labels Jun 11, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review Summary

@jfversluis — new AI review results are available based on this last commit: d3c47ac.
Preserve bound Shell titles To request a fresh review after new comments or commits, comment /review rerun.

Gate Passed Code Review In Review Confidence Medium Platform Android

Review Sessions — click to expand
Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: ANDROID · Base: main · Merge base: dd5b6d2e

Test Without Fix (expect FAIL) With Fix (expect PASS)
🧪 ShellToolbarTests ShellToolbarTests ✅ FAIL — 108s ✅ PASS — 73s
🔴 Without fix — 🧪 ShellToolbarTests: FAIL ✅ · 108s
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 843 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/TestUtils/TestUtils.csproj (in 2.35 sec).
  Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 4.27 sec).
  Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 5.37 sec).
  Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 2.63 sec).
  Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 58 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 36 ms).
  Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 37 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj (in 1.34 sec).
  1 of 10 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
  Controls.Core.UnitTests -> /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.19]   Discovering: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:01.39]   Discovered:  Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:01.40]   Starting:    Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:01.59]     ShellTitleReflectsCurrentPageTitleForTitleViewBindings [FAIL]
[xUnit.net 00:00:01.59]       Assert.Equal() Failure: Strings differ
[xUnit.net 00:00:01.59]       Expected: "Test Title"
[xUnit.net 00:00:01.59]       Actual:   null
[xUnit.net 00:00:01.60]       Stack Trace:
[xUnit.net 00:00:01.60]         /_/src/Controls/tests/Core.UnitTests/ShellToolbarTests.cs(296,0): at Microsoft.Maui.Controls.Core.UnitTests.ShellToolbarTests.ShellTitleReflectsCurrentPageTitleForTitleViewBindings()
[xUnit.net 00:00:01.60]            at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
[xUnit.net 00:00:01.60]            at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
  Failed ShellTitleReflectsCurrentPageTitleForTitleViewBindings [129 ms]
  Error Message:
   Assert.Equal() Failure: Strings differ
Expected: "Test Title"
Actual:   null
  Stack Trace:
     at Microsoft.Maui.Controls.Core.UnitTests.ShellToolbarTests.ShellTitleReflectsCurrentPageTitleForTitleViewBindings() in /_/src/Controls/tests/Core.UnitTests/ShellToolbarTests.cs:line 296
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
  Passed BackButtonExecutesCommand [28 ms]
  Passed BackButtonUpdatesWhenSetToNewCommand [3 ms]
  Passed ShellTitleBindingIsNotOverwrittenByCurrentPageTitle [3 ms]
  Passed ToolBarShouldBeVisibleWithEmptyTitleAndFlyoutBehaviorSetToFlyout [1 ms]
  Passed TitleAndTitleViewAreMutuallyExclusive [4 ms]
  Passed BackButtonBehaviorCommandFromPoppedPageIsCorrectlyUnsubscribedFrom [7 ms]
  Passed BackButtonBehaviorBindingContextPropagationWithExistingBindingContext [3 ms]
  Passed ShellToolbarUpdatesFromNewBackButtonBehavior [1 ms]
[xUnit.net 00:00:01.68]   Finished:    Microsoft.Maui.Controls.Core.UnitTests
  Passed BackButtonBehaviorSet [< 1 ms]
  Passed NavBarIsVisibleUpdates [3 ms]
  Passed ContentPageColorsPropagateToShellToolbar [3 ms]
  Passed ShellToolbarItemsMergeWithPage [11 ms]
  Passed BackButtonDisabledWhenCommandDisabled [2 ms]
  Passed ShellToolbarUpdatesFromPropertyChanged [1 ms]
  Passed BackButtonBehaviorBindingContextPropagation [< 1 ms]

Test Run Failed.
Total tests: 16
     Passed: 15
     Failed: 1
 Total time: 2.2175 Seconds

🟢 With fix — 🧪 ShellToolbarTests: PASS ✅ · 73s
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14353578
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
  Controls.Core.UnitTests -> /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.41]   Discovering: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:02.82]   Discovered:  Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:02.85]   Starting:    Microsoft.Maui.Controls.Core.UnitTests
  Passed ShellTitleReflectsCurrentPageTitleForTitleViewBindings [215 ms]
  Passed BackButtonExecutesCommand [35 ms]
  Passed BackButtonUpdatesWhenSetToNewCommand [6 ms]
  Passed ShellTitleBindingIsNotOverwrittenByCurrentPageTitle [2 ms]
  Passed ToolBarShouldBeVisibleWithEmptyTitleAndFlyoutBehaviorSetToFlyout [1 ms]
  Passed TitleAndTitleViewAreMutuallyExclusive [5 ms]
  Passed BackButtonBehaviorCommandFromPoppedPageIsCorrectlyUnsubscribedFrom [9 ms]
  Passed BackButtonBehaviorBindingContextPropagationWithExistingBindingContext [3 ms]
  Passed ShellToolbarUpdatesFromNewBackButtonBehavior [1 ms]
[xUnit.net 00:00:03.28]   Finished:    Microsoft.Maui.Controls.Core.UnitTests
  Passed BackButtonBehaviorSet [< 1 ms]
  Passed NavBarIsVisibleUpdates [7 ms]
  Passed ContentPageColorsPropagateToShellToolbar [5 ms]
  Passed ShellToolbarItemsMergeWithPage [24 ms]
  Passed BackButtonDisabledWhenCommandDisabled [4 ms]
  Passed ShellToolbarUpdatesFromPropertyChanged [3 ms]
  Passed BackButtonBehaviorBindingContextPropagation [< 1 ms]

Test Run Successful.
Total tests: 16
     Passed: 16
 Total time: 4.6506 Seconds

📁 Fix files reverted (2 files)
  • eng/pipelines/ci-copilot.yml
  • src/Controls/src/Core/ShellToolbar.cs

UI Tests — Shell

Detected UI test categories: Shell

Deep UI tests — 0 passed; 1 category setup failure (307 impacted tests marked failed by TRX) across 1 category on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
Shell 0/307 (setup failed; 307 marked failed)
⚠️ Shell — fixture setup failed for 307 tests

NUnit reported a OneTimeSetUp/fixture setup failure before test bodies ran; the TRX marked each affected test failed.

Multiple setup failure signatures were present; showing the first one. See the TRX artifact for all details.

OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
   at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
   at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
   at Microsoft.Maui.TestCases.Tests.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
   at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_GalleryUITest.cs:line 57
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 221
   at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)


Pre-Flight — Context & Validation

Issue: #35800 - unavailable (GitHub CLI authentication unavailable)
PR: #35800 - unavailable (local branch pr-review-35800)
Platforms Affected: android requested for testing; product change is shared Shell/Controls logic
Files Changed: 7 implementation/infrastructure, 2 test (local diff against origin/main)

Key Findings

  • GitHub CLI was unauthenticated, so PR body, linked issue text, PR comments, inline review comments, and CI checks could not be fetched. Context was gathered from the checked-out PR branch and local diff only.
  • The functional product fix is isolated to src/Controls/src/Core/ShellToolbar.cs; the regression tests are in src/Controls/tests/Core.UnitTests/ShellToolbarTests.cs.
  • The PR changes ShellToolbar.UpdateTitle() so Shell.Title mirrors the effective current page/content title via SetValueFromRenderer unless Shell.Title is already user-set or bound, while keeping Toolbar.Title empty when TitleView is present.
  • The reported scenario appears to be TitleView content binding to Shell.Title: when a TitleView is used, the native toolbar title is intentionally empty, but logical shell title bindings still need the current page title.

Code Review Summary

Verdict: LGTM
Confidence: medium
Errors: 0 | Warnings: 1 | Suggestions: 3

Key code review findings:

  • ⚠️ The current PR updates Shell.Title on every title update, even when no TitleView is present. This may be acceptable and internally consistent, but it is broader than the TitleView-specific regression.
  • 💡 Add adjacent tests for manually-set Shell.Title, navigation/push/pop title changes, ShellContent fallback, and source binding updates after TitleView is applied.
  • 💡 Consider an equality guard before SetValueFromRenderer to avoid a reentrant no-op UpdateTitle() pass after the framework-owned title write.
  • 💡 A Shell-owned helper would be architecturally cleaner if effective-title ownership needs to grow, but is more invasive than the current PR.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #35800 ShellToolbar.UpdateTitle() computes effective current title, writes it to Shell.Title with framework specificity unless user-owned, and keeps native toolbar title empty with TitleView ✅ PASSED (Gate) src/Controls/src/Core/ShellToolbar.cs, src/Controls/tests/Core.UnitTests/ShellToolbarTests.cs Original PR; gate result supplied by caller

Code Review — Deep Analysis

Code Review — PR #35800

Independent Assessment

What this changes: ShellToolbar.UpdateTitle() now computes the current effective page/content title even when a TitleView is present. It mirrors that title into Shell.Title using SetValueFromRenderer(Shell.TitleProperty, title) unless Shell.Title is already user-set or bound. The toolbar's native Toolbar.Title remains empty when TitleView exists.
Inferred motivation: TitleView content can bind to Shell.Title; previously, the early return for TitleView left the logical shell title stale or empty even though the current page had a title.

Reconciliation with PR Narrative

Author claims: GitHub PR narrative was unavailable because gh is not authenticated in this environment.
Agreement/disagreement: Local code and tests indicate the PR fixes logical Shell title propagation for TitleView bindings while preserving explicit/bound app-level Shell titles.

Findings

⚠️ Warning — Broader Shell.Title synchronization than TitleView-only scenario

The PR updates Shell.Title from the current page/content title on every UpdateTitle() call, even when no TitleView exists. That may be desirable consistency, but it is broader than the TitleView-specific failure mode and could affect app code observing Shell.Title.

💡 Suggestion — Add adjacent regression tests

The added tests cover the core TitleView binding scenario and a bound Shell.Title preservation case. Adjacent coverage would be stronger for manually-set Shell.Title, navigation/push/pop title transitions, ShellContent title fallback, and source binding updates after TitleView is applied.

💡 Suggestion — Avoid reentrant no-op title updates

SetValueFromRenderer(Shell.TitleProperty, title) may raise Shell.Title changed, which the ShellToolbar constructor handles by calling UpdateTitle() again. This should terminate because the second write is the same value, but an equality guard would avoid the extra pass.

Devil's Advocate

The current PR's use of SetValueFromRenderer is consistent with MAUI's specificity model and the added IsShellTitleSetByUser() guard prevents overwriting user or binding-owned shell titles. The main concern is behavioral scope, not a concrete correctness failure. Narrower alternatives reduce blast radius but risk inconsistent Shell.Title semantics depending on whether a TitleView is currently applied.

Verdict: LGTM

Confidence: medium
Summary: The current PR is a reasonable targeted fix with correct preservation of user-owned Shell.Title. Alternatives should be compared mainly on blast radius, abstraction ownership, and test coverage; no blocking defect was found in the PR product change from local review.


Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix Shell-owned effective title helper ✅ PASS 2 files Moves Shell.Title ownership/specificity guard into Shell; cleaner abstraction but more invasive than PR.
2 try-fix TitleView-only Shell.Title synchronization ✅ PASS 1 file Reduces blast radius but makes Shell.Title tracking depend on TitleView presence.
3 try-fix Handler-specific binding from current Page.Title ✅ PASS / ⚠️ self-review finding 1 file Uses binding infrastructure but misses ShellContent.Title fallback when Page.Title is unset.
PR PR #35800 Compute effective title in ShellToolbar, write framework-owned Shell.Title unless user-owned, keep Toolbar.Title empty with TitleView ✅ PASSED (Gate) 2 files Original PR; gate result supplied by caller.

Cross-Pollination

Model Round New Ideas? Details
maui-expert-reviewer 2 No NO NEW IDEAS — remaining distinct options such as an internal effective-title property/coercion model or binding proxy are more invasive and not likely better than the PR.

Exhausted: Yes
Selected Fix: PR #35800 — It passes the supplied gate, preserves effective title fallback semantics, protects explicit/bound Shell.Title values, and is simpler/more consistent than the passing alternatives. Candidate #1 is viable but more invasive; Candidate #2 is narrower but semantically inconsistent; Candidate #3 is not robust because it drops ShellContent fallback.

Attempt Details

  • try-fix-1/content.md — Shell-owned helper candidate, passed focused ShellToolbar tests.
  • try-fix-2/content.md — TitleView-only synchronization candidate, passed focused ShellToolbar tests.
  • try-fix-3/content.md — Binding-driven candidate, passed focused ShellToolbar tests but has a major self-review finding.

Report — Final Recommendation

Comparative Fix Report

Candidates

Rank Candidate Regression status Assessment
1 pr PASS Best choice. It fixes the TitleView/Shell.Title binding regression, preserves ShellContent fallback semantics, protects explicit or bound Shell.Title values, and keeps the change localized to the existing toolbar title update path.
1 pr-plus-reviewer PASS Equivalent to pr; the expert reviewer found no actionable changes to apply. It is not selected separately because it has no behavioral or code delta over the submitted PR.
3 try-fix-1 PASS Viable Shell-owned helper approach with a clean ownership boundary and equality guard, but it is more invasive because it adds new internal Shell surface for a targeted toolbar synchronization issue.
4 try-fix-2 PASS Lower blast radius than the PR because it synchronizes Shell.Title only when a TitleView is active, but that makes logical Shell title semantics depend on TitleView presence.
5 try-fix-3 PASS / self-review issue Ranked lowest among passing candidates. Its binding-driven approach misses the existing ShellContent.Title fallback when Page.Title is unset, and its recorded attempt included trim/compile concerns before correction.

No candidate with a failed regression result outranks a passing candidate. All viable candidates passed the focused regression signal recorded in STEP 5a, while try-fix-3 carries a correctness gap despite its eventual focused test pass.

Winning candidate

Winner: pr

The submitted PR fix is the best candidate because it is localized, passes the supplied gate, preserves the existing effective-title fallback behavior, and correctly avoids overwriting user-owned or bound Shell.Title values. pr-plus-reviewer is equivalent because the expert reviewer produced no actionable changes; the other try-fix candidates are either more invasive, semantically narrower, or less complete.


Future Action — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 12, 2026
@kubaflo
kubaflo changed the base branch from main to inflight/current June 12, 2026 11:18
@kubaflo
kubaflo merged commit b5a693b into inflight/current Jun 12, 2026
27 of 31 checks passed
@kubaflo
kubaflo deleted the jfversluis/fix-shell-title-binding branch June 12, 2026 11:18
@github-actions github-actions Bot added this to the .NET 10 SR9 milestone Jun 12, 2026
PureWeen pushed a commit that referenced this pull request Jun 22, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

`Shell.TitleView` content can bind to the Shell instance, but
`Shell.Title` was not updated from the active page title. This meant
bindings such as `{Binding Title, Source={x:Reference Shell}}` resolved
to `null` even when the current `ContentPage.Title` was set.

This change mirrors the effective current page or ShellContent title
into `Shell.Title` when Shell does not already have a user-set title.
The rendered toolbar title still remains empty while a custom TitleView
is active, and explicit Shell titles continue to work for Window title
fallback.

A core unit test covers the TitleView binding scenario and verifies
updates when the current page title changes.

### Issues Fixed

Fixes #35761

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kubaflo pushed a commit that referenced this pull request Jun 25, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

`Shell.TitleView` content can bind to the Shell instance, but
`Shell.Title` was not updated from the active page title. This meant
bindings such as `{Binding Title, Source={x:Reference Shell}}` resolved
to `null` even when the current `ContentPage.Title` was set.

This change mirrors the effective current page or ShellContent title
into `Shell.Title` when Shell does not already have a user-set title.
The rendered toolbar title still remains empty while a custom TitleView
is active, and explicit Shell titles continue to work for Window title
fallback.

A core unit test covers the TitleView binding scenario and verifies
updates when the current page title changes.

### Issues Fixed

Fixes #35761

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kubaflo pushed a commit that referenced this pull request Jul 3, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

`Shell.TitleView` content can bind to the Shell instance, but
`Shell.Title` was not updated from the active page title. This meant
bindings such as `{Binding Title, Source={x:Reference Shell}}` resolved
to `null` even when the current `ContentPage.Title` was set.

This change mirrors the effective current page or ShellContent title
into `Shell.Title` when Shell does not already have a user-set title.
The rendered toolbar title still remains empty while a custom TitleView
is active, and explicit Shell titles continue to work for Window title
fallback.

A core unit test covers the TitleView binding scenario and verifies
updates when the current page title changes.

### Issues Fixed

Fixes #35761

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kubaflo kubaflo mentioned this pull request Jul 6, 2026
kubaflo pushed a commit that referenced this pull request Jul 6, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

`Shell.TitleView` content can bind to the Shell instance, but
`Shell.Title` was not updated from the active page title. This meant
bindings such as `{Binding Title, Source={x:Reference Shell}}` resolved
to `null` even when the current `ContentPage.Title` was set.

This change mirrors the effective current page or ShellContent title
into `Shell.Title` when Shell does not already have a user-set title.
The rendered toolbar title still remains empty while a custom TitleView
is active, and explicit Shell titles continue to work for Window title
fallback.

A core unit test covers the TitleView binding scenario and verifies
updates when the current page title changes.

### Issues Fixed

Fixes #35761

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

`Shell.TitleView` content can bind to the Shell instance, but
`Shell.Title` was not updated from the active page title. This meant
bindings such as `{Binding Title, Source={x:Reference Shell}}` resolved
to `null` even when the current `ContentPage.Title` was set.

This change mirrors the effective current page or ShellContent title
into `Shell.Title` when Shell does not already have a user-set title.
The rendered toolbar title still remains empty while a custom TitleView
is active, and explicit Shell titles continue to work for Window title
fallback.

A core unit test covers the TitleView binding scenario and verifies
updates when the current page title changes.

### Issues Fixed

Fixes #35761

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

`Shell.TitleView` content can bind to the Shell instance, but
`Shell.Title` was not updated from the active page title. This meant
bindings such as `{Binding Title, Source={x:Reference Shell}}` resolved
to `null` even when the current `ContentPage.Title` was set.

This change mirrors the effective current page or ShellContent title
into `Shell.Title` when Shell does not already have a user-set title.
The rendered toolbar title still remains empty while a custom TitleView
is active, and explicit Shell titles continue to work for Window title
fallback.

A core unit test covers the TitleView binding scenario and verifies
updates when the current page title changes.

### Issues Fixed

Fixes #35761

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kubaflo pushed a commit that referenced this pull request Jul 9, 2026
…tive window/status bar (#36334)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details
Due to the changes introduced in PR #35800, when using Shell on Windows
and macOS (Mac Catalyst), the current page's title (intended for the
in-app navigation/title bar) was also being displayed in the native
window title bar and status bar.

### Description of Changes

<!-- Enter description of the fix in this section -->
The SetValueFromRenderer(Shell.TitleProperty, title) call was moved
inside the if (TitleView != null) block, so Shell.Title is only updated
by the renderer when a TitleView is present. Without a TitleView,
Shell.Title is left untouched, preventing the page title from
propagating to the native window/status bar.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #36225 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [ ] Android
- [x] Windows
- [ ] iOS
- [ ] Mac


| Before  | After  |
|---------|--------|
| **Mac**<br> <img
src="https://github.com/user-attachments/assets/fa030b4b-6199-429e-a74a-ed346e118e79"
width="600" height="300"> | **Mac**<br> <img
src="https://github.com/user-attachments/assets/491d4a74-6acf-458a-8d45-fe3dce25f22f"
width="600" height="300"> |

---------
kubaflo pushed a commit that referenced this pull request Jul 10, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

`Shell.TitleView` content can bind to the Shell instance, but
`Shell.Title` was not updated from the active page title. This meant
bindings such as `{Binding Title, Source={x:Reference Shell}}` resolved
to `null` even when the current `ContentPage.Title` was set.

This change mirrors the effective current page or ShellContent title
into `Shell.Title` when Shell does not already have a user-set title.
The rendered toolbar title still remains empty while a custom TitleView
is active, and explicit Shell titles continue to work for Window title
fallback.

A core unit test covers the TitleView binding scenario and verifies
updates when the current page title changes.

### Issues Fixed

Fixes #35761

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kubaflo pushed a commit that referenced this pull request Jul 10, 2026
…tive window/status bar (#36334)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details
Due to the changes introduced in PR #35800, when using Shell on Windows
and macOS (Mac Catalyst), the current page's title (intended for the
in-app navigation/title bar) was also being displayed in the native
window title bar and status bar.

### Description of Changes

<!-- Enter description of the fix in this section -->
The SetValueFromRenderer(Shell.TitleProperty, title) call was moved
inside the if (TitleView != null) block, so Shell.Title is only updated
by the renderer when a TitleView is present. Without a TitleView,
Shell.Title is left untouched, preventing the page title from
propagating to the native window/status bar.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Fixes #36225 

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

**Tested the behavior in the following platforms.**
- [ ] Android
- [x] Windows
- [ ] iOS
- [ ] Mac


| Before  | After  |
|---------|--------|
| **Mac**<br> <img
src="https://github.com/user-attachments/assets/fa030b4b-6199-429e-a74a-ed346e118e79"
width="600" height="300"> | **Mac**<br> <img
src="https://github.com/user-attachments/assets/491d4a74-6acf-458a-8d45-fe3dce25f22f"
width="600" height="300"> |

---------
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-shell Shell Navigation, Routes, Tabs, Flyout s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shell.Title evaluates to null, preventing binding inside Shell.TitleView

3 participants