Skip to content

[Windows] TabbedPage: Refresh layout when NavigationView size changes#26217

Open
BagavathiPerumal wants to merge 5 commits intodotnet:mainfrom
BagavathiPerumal:fix-26103
Open

[Windows] TabbedPage: Refresh layout when NavigationView size changes#26217
BagavathiPerumal wants to merge 5 commits intodotnet:mainfrom
BagavathiPerumal:fix-26103

Conversation

@BagavathiPerumal
Copy link
Copy Markdown
Contributor

@BagavathiPerumal BagavathiPerumal commented Nov 29, 2024

Root cause

The issue arises because the OnNavigationViewSizeChanged method fails to properly reset the layout measurements before arranging the NavigationView. As a result, the NavigationView does not correctly update its layout in response to size changes, causing misalignment or rendering issues in the ScrollView.

Description of Issue Fix

The fix involves updating the OnNavigationViewSizeChanged() method to include a call to InvalidateMeasure() before arranging the NavigationView. This ensures that the layout is accurately recalculated, allowing the ScrollView and other elements within the TabbedPage to be properly measured and arranged during the subsequent layout cycle. This effectively resolves alignment and rendering issues.

Additionally, the Arrange() call is retained within the SizeChanged handler to prevent test failures, specifically avoiding timeout issues observed in the ChangingToNewMauiContextDoesntCrash test. This combination ensures stable layout behavior while resolving the clipping and scrolling issues that occur after window resizing.

Why Tests were not added:

Regarding the test case: The issue only occurs when resizing the window, so it is not possible to add a test case for the window resizing behavior.

Tested the behavior in the following platforms.

  • Windows
  • Mac
  • iOS
  • Android

Issues Fixed

Fixes #26103
Fixes #11402
Fixes #20028

Resaved Test snapshots

Resaved the below-mentioned test snapshot because elements in the TabbedPage were not properly aligned before the fix. The layout changes in OnNavigationViewSizeChanged (adding Arrange() after InvalidateMeasure()) now ensure proper element alignment within the TabbedPage.

  1. DefaultSelectedTabTextColorShouldApplyProperly
  2. FontImageSourceColorShouldApplyOnTabIcon
  3. VerifyTabbedPageMenuItemTextColor
  4. DynamicFontImageSourceColorShouldApplyOnTabIcon
  5. Issue1323Test
  6. TabBarIconsShouldAutoscaleTabbedPage

Output

Before Issue Fix After Issue Fix
BeforeFix-TabbedPage-ScrollView.mp4
AfterFix-TabbedPage-ScrollView.mp4

@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Nov 29, 2024
@jsuarezruiz
Copy link
Copy Markdown
Contributor

jsuarezruiz commented Nov 29, 2024

/azp run

@azure-pipelines

This comment was marked as outdated.

@BagavathiPerumal BagavathiPerumal marked this pull request as ready for review November 29, 2024 11:40
@BagavathiPerumal BagavathiPerumal requested a review from a team as a code owner November 29, 2024 11:40
@BagavathiPerumal
Copy link
Copy Markdown
Contributor Author

@PureWeen / @jsuarezruiz, We have analysed the test case (Issue1323Test) failure and found that the issue was caused by a button alignment-related issue. Previously, the button inside the page, which was added as a child within the TabbedPage, was not properly aligned in the center.

In this test case, the button was added directly as the content of the page without any additional properties. However, when the page was added as a child page within the TabbedPage, the button was not properly centered.

After the fix, the button inside the page, which was added as a child in the TabbedPage, was properly aligned in the center of the page.

The fix involved calling this.InvalidateMeasure(), which triggered a layout recalculation. This allowed the element within the TabbedPage to be measured and arranged correctly during the subsequent layout cycle.

As a result, the button was properly aligned in the center of the page. Previously, the layout measurements were not recalculated, which caused the button to be misaligned on the page.

Based on the current behavior after the fix, can we resave the current snapshot as the expected snapshot for this test case (Issue1323Test).

Button Alignment in the Page (Output image from the simple sample):

image

Page added as Child in the TabbedPge(Output image from the simple sample):

image

Testcase Image (Before Fix):

image

Current Testcase Image (After Fix):

image

@sheiksyedm sheiksyedm added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Dec 6, 2024
{
if (_navigationView != null)
{
this.InvalidateMeasure();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you remove the call to this.Arrange and leave this.InvalidateMeasure does this all still work?

The call to arrange inside the SizeChanged method here doesn't seem correct.

Also, can you add a test?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@PureWeen, I have implemented the suggested changes, tested the fix across all basic scenarios, and also ran UI tests.

Testcase: The test case cannot be created for this scenario as resizing the window to a minimized state is not feasible during testing. Therefore, we have not added a test case for this scenario. Could you suggest alternative ways to address this, since resizing the window to a minimized state isn't possible during testing.

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.

Do you need to resize the Window or minimize and maximize it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@jsuarezruiz, The issue occurs only when resizing the window. Could you please share your suggestions on how to resolve it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@PureWeen, The Arrange() call in the NavigationView SizeChanged method is necessary to prevent test failures. Without this change, the ChangingToNewMauiContextDoesntCrash test consistently fails with a timeout exception.

@jsuarezruiz
Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

This comment was marked as off-topic.

1 similar comment
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 3 pipeline(s).

@Mark-NC001
Copy link
Copy Markdown

@BagavathiPerumal I've tried your pr with my app and it does appear to fix the issue, thanks!

@BagavathiPerumal
Copy link
Copy Markdown
Contributor Author

@BagavathiPerumal I've tried your pr with my app and it does appear to fix the issue, thanks!

@Mark-NC001, Thank you so much for taking the time to test the PR with your app. We're truly glad to hear that it resolves the issue.

@jfversluis jfversluis requested a review from PureWeen January 24, 2025 19:27
Copy link
Copy Markdown
Contributor

@jsuarezruiz jsuarezruiz left a comment

Choose a reason for hiding this comment

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

The test Issue1323Test related with TabbedPage and Navigation is failing on Windows. Small snapshot differences.
image

{
if (_navigationView != null)
{
this.InvalidateMeasure();
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.

Do you need to resize the Window or minimize and maximize it?

@BagavathiPerumal
Copy link
Copy Markdown
Contributor Author

The test Issue1323Test related with TabbedPage and Navigation is failing on Windows. Small snapshot differences. image

@jsuarezruiz, It looks expected behavior, as we already mentioned here, can we resave the current snapshot as the expected snapshot for this test case (Issue1323Test).

#26217 (comment)

@jsuarezruiz
Copy link
Copy Markdown
Contributor

/rebase

@jsuarezruiz
Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 3 pipeline(s).

Copy link
Copy Markdown
Contributor

@jsuarezruiz jsuarezruiz left a comment

Choose a reason for hiding this comment

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

Could be possible to include a test case for this changes?

In Appium, can minimize and maximize the Window (even change the Window size) using:

app.Driver.Manage().Window.Maximize();
app.Driver.Manage().Window.Maximize();

Let me know if can help in someway.

@BagavathiPerumal
Copy link
Copy Markdown
Contributor Author

Could be possible to include a test case for this changes?

In Appium, can minimize and maximize the Window (even change the Window size) using:

app.Driver.Manage().Window.Maximize();
app.Driver.Manage().Window.Maximize();

Let me know if can help in someway.

@jsuarezruiz, As suggested, I have tried recreating the test case using Appium but was unable to do so for this scenario. A NotImplementedException occurs when attempting to set the size value using testApp.Driver.Manage().Window.Size.

Exception details:

System.NotImplementedException: Unhandled endpoint: /session/2EDC486C-4A59-4E60-8C80-3EC866B72868/window/rect -- http://127.0.0.1:10100/ with parameters {
wildcards = (
"session/2EDC486C-4A59-4E60-8C80-3EC866B72868/window/rect"
);
}
at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary2 parameters) at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary2 parameters)
at OpenQA.Selenium.Window.set_Size(Size value)
at Microsoft.Maui.TestCases.Tests.Issues.Issue26103.VerifyTabbedPageScrollingBehavior() in /Users/bagavathi/Downloads/maui-fix-26103/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26103.cs:line 25
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

Code:

using Microsoft.Maui.Controls.PlatformConfiguration;
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues
{
    public class Issue26103 : _IssuesUITest
    {
        public Issue26103(TestDevice testDevice) : base(testDevice)
        {
        }
        public override string Issue => "TabbedPage - ScrollView not allowing scrolling when it should";
        [Test]
        [Category(UITestCategories.TabbedPage)]
        public void VerifyTabbedPageScrollingBehavior()
        {
            var testApp = (App as AppiumApp);
            if (testApp != null && testApp.Driver != null)
            {
                var originalWindowSize = testApp.Driver.Manage().Window.Size;
                testApp.Driver.Manage().Window.Size = new System.Drawing.Size(100, 200);
                testApp.WaitForElement("stackLayout1");
                VerifyScreenshot();
                testApp.Driver.Manage().Window.Size = originalWindowSize;
            }
        }
    }
}

I also tried creating a test case based on a button click to change the window size, but this approach did not reproduce the issue. The issue only occurs when resizing the window by dragging. Could you please share your suggestions on how to resolve it.

Copy link
Copy Markdown
Contributor

@jsuarezruiz jsuarezruiz left a comment

Choose a reason for hiding this comment

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

There are some TabbedPage Windows tests failing.

Issue1323Test
Snapshot different than baseline: Issue1323Test.png (0.90% difference)
image
(in red, the differences)

TestPageDoesntCrash

 at UITest.Appium.HelperExtensions.Tap(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 302
  at UITest.Appium.HelperExtensions.Tap(IApp app, IQuery query) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 38
  at UITest.Appium.HelperExtensions.TapMoreButton(IApp app) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2261
  at Microsoft.Maui.TestCases.Tests.Issues.Issue2809.TestPageDoesntCrash() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue2809.cs:line 19
  at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
  at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

Could you review if are related with the changes?

@BagavathiPerumal
Copy link
Copy Markdown
Contributor Author

There are some TabbedPage Windows tests failing.

Issue1323Test Snapshot different than baseline: Issue1323Test.png (0.90% difference) image (in red, the differences)

TestPageDoesntCrash

 at UITest.Appium.HelperExtensions.Tap(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 302
  at UITest.Appium.HelperExtensions.Tap(IApp app, IQuery query) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 38
  at UITest.Appium.HelperExtensions.TapMoreButton(IApp app) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2261
  at Microsoft.Maui.TestCases.Tests.Issues.Issue2809.TestPageDoesntCrash() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue2809.cs:line 19
  at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
  at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

Could you review if are related with the changes?

@jsuarezruiz,

Case1: Issue1323Test

It looks expected behavior, as we already mentioned here, can we resave the current snapshot as the expected snapshot for this test case (Issue1323Test).

#26217 (comment)

Case2: TestPageDoesntCrash

I have verified that the test case failures are unrelated to the fix. This has been confirmed on a local machine.

@jsuarezruiz
Copy link
Copy Markdown
Contributor

/rebase

Copilot AI review requested due to automatic review settings October 27, 2025 10:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@BagavathiPerumal BagavathiPerumal changed the title Fix for TabbedPage - ScrollView not allowing scrolling when it should [Windows]Fix for TabbedPage - ScrollView not allowing scrolling when it should Dec 8, 2025
@kubaflo kubaflo added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues 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 Mar 18, 2026
@github-actions
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 -- 26217

Or

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

@BagavathiPerumal BagavathiPerumal changed the title [Windows]Fix for TabbedPage - ScrollView not allowing scrolling when it should [Windows] TabbedPage: Refresh layout when NavigationView size changes Mar 19, 2026
@BagavathiPerumal
Copy link
Copy Markdown
Contributor Author

🤖 AI Summary

📊 Expand Full Reviewfc7ca15 · fix-26103-Resaved the test image.
🔍 Pre-Flight — Context & Validation
Issue: #26103 - TabbedPage - ScrollView not allowing scrolling when it should Related Issues: #11402 - TabbedPage App on resize hides page bottom content; #20028 - Grid overflows child ContentPage of parent TabbedPage on initial load and when resizing on Windows PR: #26217 - [Windows]Fix for TabbedPage - ScrollView not allowing scrolling when it should Platforms Affected: Windows Files Changed: 1 implementation, 6 test snapshot baselines

Key Findings

  • All three linked issues describe the same Windows-only TabbedPage resize/layout problem: child page content shifts or overflows after window resize, causing lost bottom content or incorrect ScrollView extent.
  • The PR changes src\Controls\src\Core\TabbedPage\TabbedPage.Windows.cs and resaves six WinUI snapshot baselines, but it does not add a new executable regression test for the resize behavior reviewers requested.
  • Reviewer feedback specifically questioned whether Arrange() is necessary in the size-changed handler and repeatedly asked for a test that proves the fix.
  • PR discussion indicates Issue1323Test snapshot drift was treated as expected fallout from the layout change, while another failing test (Issue2809) was reported as unrelated.
  • A user comment on the PR confirms the branch appears to fix their real app, but pre-flight does not validate that claim.

Edge Cases / Discussion Notes

  • The issue is triggered by window resizing on Windows; one report notes width changes can toggle whether the ScrollView reaches the bottom.
  • Another related issue reports the broken layout can be present on initial load and then behave inconsistently as the window shrinks.
  • The author reports Appium window resizing hit a NotImplementedException, which explains why the PR currently lacks a direct UI regression test.

Fix Candidates

Source Approach Test Result Files Changed Notes

PR PR #26217 In OnNavigationViewSizeChanged, call InvalidateMeasure() and then Arrange(_navigationView) so TabbedPage remeasures/rearranges after NavigationView size changes; resave affected WinUI snapshots PENDING (Gate) src\\Controls\\src\\Core\\TabbedPage\\TabbedPage.Windows.cs, snapshot baselines Original PR; reviewers requested proof that Arrange() is required and asked for a real test
🚦 Gate — Test Verification

Gate Result: SKIPPED

Platform: Windows Mode: Full Verification

  • Tests in PR (TestCases.HostApp / TestCases.Shared.Tests): None added
  • Tests FAIL without fix: N/A
  • Tests PASS with fix: N/A

Notes:

  • The PR modifies one implementation file and six Windows snapshot baselines, but it does not add a HostApp page or Shared UI test for the resize/scroll regression.
  • Because no PR-added executable regression test exists, the required fail-without-fix / pass-with-fix verification could not be performed.
  • Reviewer feedback on the PR explicitly requested a test, and the author noted Appium window resizing hit NotImplementedException, which appears to be why coverage is still missing.

🔧 Fix — Analysis & Comparison

Fix Candidates

Source Approach Test Result Files Changed Notes

1 try-fix (claude-opus-4.6) Invalidate _displayedPage on NavigationView size change and rely on the normal layout cycle instead of explicitly calling Arrange(_navigationView) PASS 1 file More targeted than the PR; directly addresses reviewer concern about Arrange()
2 try-fix (claude-sonnet-4.6) Call _navigationFrame?.UpdateLayout() on NavigationView size change to force a synchronous WinUI layout pass of the tab content subtree PASS 1 file Platform-level alternative; also removes the explicit Arrange() call
3 try-fix (gpt-5.3-codex) Clear cached _displayedPage and call UpdateCurrentPageContent() on NavigationView size change to refresh and remeasure the active tab content PASS 3 files during attempt Passing alternative, but it touched test files during the attempt to validate a new scenario
4 try-fix (gemini-3-pro-preview) Call _navigationFrame?.InvalidateMeasure() on NavigationView size change instead of invalidating the TabbedPage or arranging the NavigationView PASS 1 file Targeted content-frame invalidation also passes the proxy test
5 try-fix (claude-opus-4.6) Defer into the dispatcher and invalidate the nested ContentPresenter (InvalidateMeasure + InvalidateArrange) after NavigationView finishes resizing PASS 1 file Post-layout subtree invalidation also succeeds under the same proxy test
6 try-fix (claude-sonnet-4.6) Call _navigationView?.InvalidateArrange() on size change so native WinUI re-arranges the container and its children PASS 1 file Cleanest single-call WinUI-native alternative among the passing candidates
7 try-fix (gemini-3-pro-preview) Hook _navigationFrame.SizeChanged and react there instead of _navigationView.SizeChanged FAIL 1 file Failed the Windows proxy test with snapshot difference, suggesting the frame hook misses the real trigger
8 try-fix (claude-opus-4.6) Wrap the frame in a custom Grid host that invalidates the displayed page during arrange-size changes FAIL 1 file More invasive visual-tree rewrite caused a 0.89% snapshot difference
9 try-fix (gemini-3-pro-preview) Set _navigationView.HorizontalContentAlignment and .VerticalContentAlignment to Stretch and remove the size-change nudges PASS 1 file Declarative alternative, but root-cause confidence is lower than candidate 6
PR PR #26217 Invalidate the TabbedPage and explicitly call Arrange(_navigationView) in OnNavigationViewSizeChanged; resave affected WinUI snapshots NOT GATED 1 implementation file + 6 snapshot baselines No dedicated regression test was added, so Gate could not verify fail-without-fix / pass-with-fix

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 1 Yes Invalidate/arrange the ContentPresenter child in a deferred post-layout callback.
claude-sonnet-4.6 1 Yes Call _navigationView?.InvalidateArrange() on size change.
gpt-5.3-codex 1 No NO NEW IDEAS
gemini-3-pro-preview 1 Yes Hook _navigationFrame size changes instead of _navigationView and react to the actual content area size.
claude-opus-4.6 2 Yes Replace manual size-change nudges with a custom Grid host that naturally stretches the NavigationView/Frame.
claude-sonnet-4.6 2 No NO NEW IDEAS
gpt-5.3-codex 2 No NO NEW IDEAS
gemini-3-pro-preview 2 Yes Force _navigationView content alignments to Stretch.
claude-opus-4.6 3 Yes Custom LayoutPanel host that explicitly measures/arranges current page on every size change.
claude-sonnet-4.6 3 No NO NEW IDEAS
gpt-5.3-codex 3 No NO NEW IDEAS
gemini-3-pro-preview 3 No NO NEW IDEAS
Exhausted: No reached the 3-round cross-pollination limit with one remaining architectural rewrite idea untried. Selected Fix: Candidate #6 (_navigationView?.InvalidateArrange()) simplest passing WinUI-native fix among the tried alternatives, though confidence is limited because the PR still lacks a dedicated fail-without-fix / pass-with-fix regression test.

📋 Report — Final Recommendation

Final Recommendation: REQUEST CHANGES

Phase Status

Phase Status Notes
Pre-Flight COMPLETE Windows-only TabbedPage resize/layout bug; PR changes 1 implementation file and 6 WinUI snapshot baselines.
Gate SKIPPED PR adds no dedicated TestCases.HostApp / TestCases.Shared.Tests regression test, so fail-without-fix / pass-with-fix verification could not be run.
Try-Fix COMPLETE 9 attempts run, 7 passing and 2 failing; multiple materially different alternatives passed the current Windows proxy test.
Report COMPLETE

Summary

The PR is addressing a real Windows TabbedPage resize bug, but it still should not be approved in its current form. The main blocker is test quality: there is no dedicated regression test for the resize/scroll scenario reviewers asked for, so the gate had to be skipped. In try-fix, seven materially different alternatives passed the available proxy test (Issue1323Test), which means the current validation is too weak to show that the PR's specific InvalidateMeasure() + Arrange() fix is necessary or best.

Root Cause

The underlying problem appears to be stale layout propagation after NavigationView size changes on Windows TabbedPage hosting. Child content (especially the frame/ScrollView subtree) is not consistently remeasured or rearranged when the container resizes, causing clipped bottom content or incorrect scroll extent after window resize.

Fix Quality

The PR fix is plausible, but it is heavier than necessary and still unproven. Reviewer feedback specifically questioned the explicit Arrange() call, and try-fix found cleaner passing alternatives such as candidate #6 (_navigationView?.InvalidateArrange()) and candidate #1 (_displayedPage?.InvalidateMeasure()). Because no dedicated regression test exists, I do not have enough evidence to recommend the PR's current implementation over those simpler options. I would request changes to add a real reproducible regression test for the resize behavior and then re-evaluate the implementation choice against that stronger test.

📋 Expand PR Finalization Review

I’ve reviewed and updated the changes based on the latest findings. Specifically:

  • Verified the AI-suggested fix on the Windows platform and confirmed that it does not resolve the issue
  • Confirmed that the suggested code changes do not address the root cause of the problem
  • Retained the existing implementation, as the AI-proposed modifications are not effective in resolving the issue
  • Checked the possibilities to add the testcase for the windows resizing behavior. However, unable to add the testcase for the windows resizing behavior.
  • Ensured the findings are aligned with the current PR status and reviewer expectations
  • The InvalidateMeasure() + immediate Arrange(...) pattern in OnNavigationViewSizeChanged() requires justification, as it is an uncommon layout approach and lacks test validation; however, Arrange() is currently necessary to prevent failures in ChangingToNewMauiContextDoesntCrash.
  • Updated the description and title based on the changes made in the PR.

@MauiBot MauiBot added the s/agent-gate-failed AI could not verify tests catch the bug label Mar 19, 2026
@dotnet dotnet deleted a comment from MauiBot Mar 19, 2026
@kubaflo
Copy link
Copy Markdown
Contributor

kubaflo commented Mar 19, 2026

/azp run maui-pr-uitests

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Mar 20, 2026

🤖 AI Summary

📊 Expand Full Reviewe4a80c4 · fix-26103-Resaved the test image.
🔍 Pre-Flight — Context & Validation

Issue: #26103 - TabbedPage - ScrollView not allowing scrolling when it should (+ #11402, #20028)
PR: #26217 - [Windows] TabbedPage: Refresh layout when NavigationView size changes
Platforms Affected: Windows (primary fix), snapshots updated for Windows
Files Changed: 1 implementation, 6 test snapshots (PNG, binary)

Key Findings

  • Root cause: When NavigationView fires SizeChanged, the MAUI layout system is not notified, so child content (ScrollViews, etc.) keeps its old measured dimensions and clips incorrectly.
  • Original code: OnNavigationViewSizeChanged already called this.Arrange(_navigationView) but had no InvalidateMeasure() — so layout constraints were stale before the arrange pass.
  • PR fix: Adds this.InvalidateMeasure() before the existing this.Arrange(_navigationView) call, ensuring MAUI re-measures before re-arranges.
  • Reviewer concern (PureWeen): Asked whether this.Arrange() is actually needed inside SizeChanged, or if InvalidateMeasure() alone would suffice. Arrange inside SizeChanged may be incorrect/unusual.
  • Author response: Removing Arrange() causes ChangingToNewMauiContextDoesntCrash device test to fail with timeout, so both calls are retained.
  • this.Arrange(): Calls the MAUI IView.Arrange(Rect) extension which forces an immediate arrange pass with (0, 0, actualWidth, actualHeight). Calling this inside a SizeChanged handler is unconventional and could cause issues (re-entrancy risk).
  • Snapshot resave: 6 Windows UI test snapshots were updated — indicating that the layout fix changes visual output of existing TabbedPage tests (alignment improved).
  • No new tests added — author claims window resizing cannot be automated. Gate was SKIPPED.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #26217 Add InvalidateMeasure() before Arrange(_navigationView) in OnNavigationViewSizeChanged ⏳ PENDING TabbedPage.Windows.cs Reviewer questions whether Arrange() is needed

🔧 Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix (claude-opus-4.6) InvalidateMeasure() only remove Arrange() entirely PASS TabbedPage.Windows.cs Simplest; aligns with reviewer's suggestion
2 try-fix (claude-sonnet-4.6) Dispatcher.Dispatch(() => InvalidateMeasure()) deferred PASS TabbedPage.Windows.cs Avoids re-entrancy but unnecessary complexity
3 try-fix (gpt-5.3-codex) LayoutUpdated event + cache dimensions + CurrentPage?.InvalidateMeasure() + Arrange() PASS TabbedPage.Windows.cs Over-engineered (+24 lines)
4 try-fix (gpt-5.4) foreach (var child in Children) child.InvalidateMeasure() PASS TabbedPage.Windows.cs Less correct parent should invalidate, not children
PR PR #26217 InvalidateMeasure() + Arrange(_navigationView) PASSED (Gate skipped) TabbedPage.Windows.cs Reviewer questioned Arrange() in SizeChanged

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 2 NO NEW IDEAS Confirmed Attempt 1 is cleanest; PR's Arrange() call is redundant

Exhausted: Yes
Selected Fix: Candidate #1 (Attempt 1) InvalidateMeasure() only. Reason: Simplest fix (1-line change), directly matches reviewer PureWeen's suggestion, removes the questionable Arrange() call from a SizeChanged handler. InvalidateMeasure() triggers a full measurearrange cycle, making the explicit Arrange() call redundant.


📋 Report — Final Recommendation

⚠️ Final Recommendation: REQUEST CHANGES

Phase Status

Phase Status Notes
Pre-Flight ✅ COMPLETE Issues #26103, #11402, #20028; Windows TabbedPage layout on resize
Gate ⚠️ SKIPPED No tests detected in PR
Try-Fix ✅ COMPLETE 4 attempts, 4 passing — better alternative found
Report ✅ COMPLETE

Summary

The PR fixes a real, long-standing Windows bug: TabbedPage content (especially ScrollViews) clips incorrectly after window resize. The fix is in OnNavigationViewSizeChanged and the core idea of calling InvalidateMeasure() is correct. However, the PR keeps the pre-existing this.Arrange(_navigationView) call alongside InvalidateMeasure(), which the reviewer (PureWeen) specifically questioned. Agent exploration found that InvalidateMeasure() alone is sufficient and simpler.

Root Cause

When NavigationView fires SizeChanged, MAUI's layout system holds stale measurements. The original code called this.Arrange(_navigationView) (forces layout with ActualWidth/ActualHeight), but skipped InvalidateMeasure(), so MAUI re-arranged using cached (pre-resize) constraint sizes — causing clipping.

Fix Quality

The PR's fix works but is suboptimal:

  • InvalidateMeasure() is the correct signal — it marks layout as dirty and schedules a proper measure→arrange cycle
  • ⚠️ The retained this.Arrange(_navigationView) call is redundant and architecturally questionable — calling IView.Arrange() synchronously inside a SizeChanged callback is unusual and could cause re-entrancy in edge cases

Better alternative (Attempt #1): Remove this.Arrange(_navigationView) and keep only this.InvalidateMeasure():

void OnNavigationViewSizeChanged(object sender, SizeChangedEventArgs e)
{
    if (_navigationView != null)
        this.InvalidateMeasure();
}

This is a 1-line change, passes the same tests, and directly implements what reviewer PureWeen suggested. It lets MAUI's layout system handle the full measure→arrange pass naturally.

Concerns

  1. No new tests — The author acknowledges window-resize scenarios can't be automated. However, the resaved snapshots suggest layout did change. Reviewer should confirm the 6 resaved snapshots are intentional improvements and not regressions.
  2. ChangingToNewMauiContextDoesntCrash timeout claim — Author says removing Arrange() causes this device test to timeout. This was NOT reproduced in try-fix (attempt 1 passed without Arrange()). The agent ran a UI test (Issue28838), not the device test. If the device test truly fails without Arrange(), it may indicate a deeper lifecycle issue that the Arrange() call is papering over.
  3. Snapshot changes — 6 Windows test snapshots were resaved. These should be reviewed carefully to confirm the layout changes are correct improvements and not unintended side-effects.

Recommendation

Request changes to:

  1. Remove the this.Arrange(_navigationView) call per reviewer suggestion — InvalidateMeasure() alone is sufficient
  2. Confirm the ChangingToNewMauiContextDoesntCrash device test still passes without Arrange() (the agent's try-fix suggests it should)
  3. Review the 6 resaved snapshots to confirm they represent correct layout (not regressions)

Copy link
Copy Markdown
Contributor

@kubaflo kubaflo left a comment

Choose a reason for hiding this comment

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

Please review the ai's summary :)

@BagavathiPerumal
Copy link
Copy Markdown
Contributor Author

Please review the ai's summary :)

I have reviewed the AI summary. The Arrange() call in the NavigationView.SizeChanged method is necessary to prevent test failures. Without this change, the ChangingToNewMauiContextDoesntCrash test consistently fails with a TimeoutException.

PureWeen pushed a commit that referenced this pull request Mar 23, 2026
#34575)

<!-- 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

Adds Windows platform support to the `maui-copilot` CI pipeline (AzDO
definition 27723), enabling Copilot PR reviews on Windows-targeted PRs.

### Changes

**`eng/pipelines/ci-copilot.yml`**
- Add `catalyst` and `windows` to Platform parameter values
- Add per-platform pool selection (`androidPool`, `iosPool`, `macPool`,
`windowsPool`)
- Skip Xcode, Android SDK, simulator setup for Windows/Catalyst
- Add Windows-specific "Set screen resolution" step (1920x1080)
- Add MacCatalyst-specific "Disable Notification Center" step
- Fix `sed` command for `Directory.Build.Override.props` on Windows (Git
Bash uses GNU sed)
- Handle Copilot CLI PATH detection on Windows vs Unix
- Change `script:` steps to `bash:` for cross-platform consistency

**`.github/scripts/Review-PR.ps1`**
- Add `catalyst` to ValidateSet for Platform parameter

**`.github/scripts/BuildAndRunHostApp.ps1`**
- Add Windows test assembly directory for artifact collection

**`.github/scripts/post-ai-summary-comment.ps1` /
`post-pr-finalize-comment.ps1`**
- Various improvements for cross-platform comment posting

### Validation

Successfully ran the pipeline with `Platform=windows` on multiple
Windows-specific PRs:
- PR #27713 — ✅ Succeeded
- PR #34337 — ✅ Succeeded
- PR #26217, #27609, #27880, #28617, #29927, #30068 — Triggered and
running

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Mar 29, 2026

🚦 Gate - Test Before and After Fix

📊 Expand Full Gatee4a80c4 · fix-26103-Resaved the test image.

Gate Result: ⚠️ SKIPPED

No tests were detected in this PR.

Recommendation: Add tests to verify the fix using the write-tests-agent:

@copilot write tests for this PR

The agent will analyze the issue, determine the appropriate test type (UI test, device test, unit test, or XAML test), and create tests that verify the fix.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-controls-tabbedpage TabbedPage community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-win AI found a better alternative fix than the PR s/agent-gate-failed AI could not verify tests catch the bug s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet