Skip to content

[release/10.0.1xx-sr10] Preserve custom iOS button styling - #37726

Merged
kubaflo merged 9 commits into
dotnet:vs/10.0.101from
kubaflo:release-agent/sr10-backport-36769
Aug 22, 2026
Merged

kubaflo merged 9 commits into
dotnet:vs/10.0.101from
kubaflo:release-agent/sr10-backport-36769

Conversation

@kubaflo

@kubaflo kubaflo commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

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!

Summary

Manual backport of #36769 to release/10.0.1xx-sr10 for .NET MAUI 10.0.101.

Validation

  • Source and SR10 patches have matching stable patch ID f5eb0ffddfe5e87e84c64060fcb73927191d00e1.
  • Core.csproj builds successfully for net10.0-ios26.0 in Release configuration with zero warnings and zero errors.

Review gate

This agent-authored release PR must remain unmerged until two distinct non-bot MAUI maintainers with write access, other than the PR author, approve the current head SHA.

Manual backport of dotnet#36769 for .NET MAUI 10.0.101.

Source head: 348f69b

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1e7f77e3-4862-4b92-a662-d12b5918bb59
Copilot AI lite review requested due to automatic review settings August 21, 2026 21:49
@kubaflo
kubaflo temporarily deployed to copilot-pat-pool August 21, 2026 21:49 — with GitHub Actions Inactive
@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 -- 37726

Or

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

@kubaflo
kubaflo temporarily deployed to copilot-pat-pool August 21, 2026 21:49 — with GitHub Actions Inactive
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

@kubaflo

kubaflo commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

/azp run

@kubaflo
kubaflo temporarily deployed to copilot-pat-pool August 21, 2026 21:53 — with GitHub Actions Inactive
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).

Copilot AI 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.

Pull request overview

Backports the iOS ButtonHandler regression fix to release/10.0.1xx-sr10 by updating the iOS UIButton background-mapping behavior to preserve native styling when Background is unset during initial handler connection, and adds a UI regression test covering the scenario.

Changes:

  • iOS: Guard UIButton.BackgroundColor = UIColor.Clear behind a Window != null check when paint is null/empty, preserving constructor-set native styling on initial render.
  • Tests: Add HostApp repro page + custom handler and a corresponding Appium UI test for issue #36749.
  • Register the custom test handler in the HostApp’s MauiProgram.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/Core/src/Platform/iOS/ButtonExtensions.cs Updates iOS button background mapping to avoid clearing native styling during initial render when Window is null.
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue36749.cs Adds an Appium UI test asserting the regression is fixed on iOS/MacCatalyst.
src/Controls/tests/TestCases.HostApp/MauiProgram.cs Registers the issue-specific custom button handler for the HostApp test page.
src/Controls/tests/TestCases.HostApp/Issues/Issue36749.cs Adds the HostApp issue page and custom ButtonHandler/UIButton subclass used to reproduce and validate the fix.

Comment thread src/Controls/tests/TestCases.HostApp/Issues/Issue36749.cs Outdated

@PureWeen PureWeen left a comment

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.

Adversarial review

💡 Regressionsrc/Core/src/Platform/iOS/ButtonExtensions.cs:74: Window == null identifies both the initial map and a previously shown button that is temporarily detached. If a button with a MAUI solid background is detached (for example, during navigation or cell reuse) and its Background becomes null, the mapper removes its gradient layer but skips BackgroundColor = UIColor.Clear. Reattaching the existing native button can therefore show the stale solid background instead of restoring the null-background state.

Use a one-time initial-map/handler-lifecycle signal rather than current window attachment, so only the true first map preserves native styling while later null-background updates always clear prior MAUI state.

Flagged by: 3/3 reviewers, including independent reviewer validation.

The added UI test covers initial native styling preservation, but not the detached-view reset path above.

Methodology: 3 independent reviewers with adversarial consensus.

Guard the nullable UIButton background before reading its RGBA components so the HostApp reports a deterministic test failure instead of crashing.

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

Copilot-Session: d00747b7-96f3-4e7a-8dfb-e3a48db04b2d
Copilot AI review requested due to automatic review settings August 21, 2026 22:37
@kubaflo

kubaflo commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@copilot addressed the latest feedback by making a missing native background color a deterministic UI-test failure. The iOS-simulator HostApp build succeeds cleanly. This is ready for re-review — thanks!

Copilot AI 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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue36749.cs:26

  • The test reads the result label immediately after WaitForElement(...), but the label is created with initial text "Checking..." and is only updated in OnAppearing() in the HostApp page. Since _IssuesUITest navigation doesn’t wait for OnAppearing, this can flake by asserting against "Checking...". Prefer waiting for the label text to become "PASS" (or timing out) using WaitForTextToBePresentInElement.
        App.WaitForElement("Issue36749Result");

        var resultText = App.FindElement("Issue36749Result").GetText();

        Assert.That(resultText, Is.EqualTo("PASS"),

Use platform-view lifecycle state rather than window attachment to preserve native styling only on the initial map, while clearing later detached updates. Extend the regression coverage for the detached-view case.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: d00747b7-96f3-4e7a-8dfb-e3a48db04b2d
Copilot AI review requested due to automatic review settings August 21, 2026 23:04
@kubaflo

kubaflo commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@PureWeen fixed in 6c898fa. ButtonExtensions now tracks the first background mapping per native UIButton with weak lifecycle state instead of inferring it from Window, so only the true initial null map preserves constructor/appearance styling and later null maps clear stale MAUI state even while detached. The Issue36749 regression now explicitly applies a red MAUI background, detaches the native view, clears the background, and requires transparent output. Core iOS Button device tests passed (97 passed, 1 skipped), and the iOS HostApp plus Appium test assembly build cleanly. Ready for re-review — thanks!

Copilot AI 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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue36749.cs:1

  • Minor: the preprocessor line comment is missing a space after // and uses "Mac Catalyst" inconsistently with the rest of the repo's "MacCatalyst" naming.
#if IOS || MACCATALYST      //This is an iOS-specific issue and can be reproduced by extending UIButton. Therefore, the test was added only for iOS and Mac Catalyst.

src/Controls/tests/TestCases.HostApp/Issues/Issue36749.cs:70

  • This comment explains the detached-null scenario in terms of a Window-based guard, but the production fix is now initial-update state tracking. Rewording to a conditional rationale avoids implying the current code uses Window checks.
		// A later null mapping must clear MAUI-applied state even while the native view is
		// detached. Window-based initial-map detection incorrectly leaves this color red.

Comment thread src/Controls/tests/TestCases.HostApp/Issues/Issue36749.cs Outdated
Comment thread src/Core/src/Platform/iOS/ButtonExtensions.cs Outdated

@PureWeen PureWeen left a comment

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.

Adversarial review

⚠️ Regressionsrc/Core/src/Platform/iOS/ButtonExtensions.cs:63 records whether a UIButton has ever received a background mapping, rather than whether the current virtual button has applied a MAUI background. ElementHandler.SetVirtualView deliberately retains an existing platform view when it reconnects that handler to a different virtual view, then reruns all property mappers. A recycled custom button whose new virtual view still has the default null Background therefore takes the later-null path and sets UIColor.Clear, wiping the native constructor styling this change is intended to preserve.

Track the initialization state per virtual-view assignment, or clear only after MAUI has applied a non-null background, and add a reconnect/reuse regression case.

Flagged by 2/3 reviewers after adversarial consensus and independent reviewer source validation.

Automated assessment complete: verified current head 6c898fa576dbeda5dd933b8421ea4e068fb7e859; sender session 20939cfd-13dd-40eb-83ee-cdb524c95e95.

Only clear a null background after MAUI applied one, and cover reconnecting the same native button to a new virtual view.

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

Copilot-Session: d00747b7-96f3-4e7a-8dfb-e3a48db04b2d
This was referenced Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants