[release/10.0.1xx-sr10] Preserve custom iOS button styling - #37726
Conversation
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
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 37726Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 37726" |
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
|
/azp run |
|
Azure Pipelines: Successfully started running 3 pipeline(s). |
There was a problem hiding this comment.
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.Clearbehind aWindow != nullcheck whenpaintis 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. |
PureWeen
left a comment
There was a problem hiding this comment.
Adversarial review
💡 Regression — src/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 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! |
There was a problem hiding this comment.
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 inOnAppearing()in the HostApp page. Since_IssuesUITestnavigation doesn’t wait forOnAppearing, this can flake by asserting against "Checking...". Prefer waiting for the label text to become "PASS" (or timing out) usingWaitForTextToBePresentInElement.
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
|
@PureWeen fixed in 6c898fa. |
There was a problem hiding this comment.
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.
PureWeen
left a comment
There was a problem hiding this comment.
Adversarial review
src/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
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-sr10for .NET MAUI 10.0.101.348f69b8e04a72d83b563064404a7c4fd79aef75.inflight/currentand has not flowed tomain; this manual port intentionally excludes unrelated inflight branch history.Validation
f5eb0ffddfe5e87e84c64060fcb73927191d00e1.Core.csprojbuilds successfully fornet10.0-ios26.0in 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.