[iOS] GraphicsView DrawString - fix#26304
Conversation
jfversluis
left a comment
There was a problem hiding this comment.
Can you rebase this one for the new GraphicsView category?
Sure thing! |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
|
/rebase |
| canvas.FontColor = Colors.Black; | ||
| canvas.FontSize = 10; | ||
| canvas.Font = Microsoft.Maui.Graphics.Font.Default; | ||
| canvas.DrawString("GraphicsText", dirtyRect.Left + dirtyRect.Width / 2, dirtyRect.Top + dirtyRect.Height / 2, HorizontalAlignment.Left); |
There was a problem hiding this comment.
Could you update the test to include multiple strings using all the different HorizontalAlignment options?
There was a problem hiding this comment.
No problem! Done :)
|
Azure Pipelines successfully started running 3 pipeline(s). |
|
@Eilon and @StephaneDelcroix please let me know what needs to be done here to make a step forward with this? Thank you for your time and effort. |
|
I want to add a little bit to my previous comment #26304 (comment). Could it be possible to extend this fix to all the |
|
Until this fix is done, please find workaround here. |
…#34317) <!-- 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 Add `darc-*` to the `trigger: branches: include:` section in `ci-uitests.yml` and `ci-device-tests.yml` so that `maui-pr-uitests` and `maui-pr-devicetests` automatically run when dotnet-maestro pushes dependency updates to `darc-*` branches. Previously, these pipelines required manual `/azp run` comments on every maestro PR. ### Issues Fixed N/A - CI improvement ### Files Changed - `eng/pipelines/ci-uitests.yml` - Added `darc-*` to CI trigger branch filter - `eng/pipelines/ci-device-tests.yml` - Added `darc-*` to CI trigger branch filter Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…otnet#34327) <!-- 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 PR dotnet#34320 fixed RS0017 analyzer errors caused by `#nullable enable` being sorted to the bottom of 14 Maps `PublicAPI.Unshipped.txt` files. The root cause was a prior Copilot agent session that used `LC_ALL=C sort -u` to resolve merge conflicts — the BOM bytes (`0xEF 0xBB 0xBF`) sort after all ASCII characters, pushing the directive below the API entries. This updates the Copilot instructions to prevent this from recurring: - Explains that `#nullable enable` must remain on line 1 - Warns against using plain `sort` on these files (BOM sort ordering) - Provides a safe conflict resolution script that preserves the header before sorting API entries Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…otnet#34301) ### Description of Change Fixes a crash on Android when using `TapGestureRecognizer` with `GraphicsView`. ### Root Cause `PlatformTouchGraphicsView.TouchesMoved` assumed that `_lastMovedViewPoints` always contained at least one element. In certain touch event sequences (triggered when a TapGestureRecognizer is attached), `_lastMovedViewPoints` could be empty while `points.Length == 1`, leading to an IndexOutOfRangeException. ### Fix Added a length check before accessing `_lastMovedViewPoints[0]` to prevent out-of-range access. ### Verified Scenarios - TapGestureRecognizer no longer causes a crash - Tap events fire correctly - Drag interaction remains functional - Multitouch does not crash Fixes dotnet#34296
…lView (dotnet#34279) > [!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! ### Root Cause PR dotnet#33281 added a `GetDesiredSize()` override in `LabelHandler.Android.cs` to fix issue dotnet#31782 (WordWrap labels reporting full constraint width instead of actual text width). The fix computes the longest wrapped line and returns that as the desired width. This causes a regression when `MaxLines` is set on the label: 1. `GetDesiredSize()` is called at the full available width — text wraps cleanly within MaxLines limit 2. The fix returns the shorter "longest line" width 3. The label is arranged at that narrower width 4. At the narrower width, the same text needs more lines — exceeding MaxLines → text is clipped ### Description of Change The `GetDesiredSize()` override now uses a double-measurement strategy: 1. **Entry guard**: Only applies the width-narrowing when `Ellipsize == null` (no active truncation). 2. **Compute candidate width**: Finds the widest rendered line as before. 3. **Safety check** (only when `MaxLines` is explicitly set): Re-measures the TextView at exactly the narrowed pixel width. If the re-measurement shows the text would now exceed `MaxLines`, the original full width is returned instead. 4. **Narrow when safe**: If the re-measurement confirms the same or fewer lines, the narrowed width is returned — preserving the dotnet#31782 alignment fix even for labels with explicit `MaxLines`. This avoids both regressions: - Labels without `MaxLines` behave as before (alignment fix preserved, no second measure). - Labels with `MaxLines` that have line-count headroom also get the alignment fix. ### Issues Fixed Fixes dotnet#34120 ### Tested platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac **Files Changed in this PR:** | File | Change | |------|--------| | `src/Core/src/Handlers/Label/LabelHandler.Android.cs` | Double-measurement fix (~20 lines) | | `src/Controls/tests/TestCases.HostApp/Issues/Issue34120.cs` | New UI test HostApp page | | `src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34120.cs` | New NUnit UI test | **Regression Reference:** - Regressed by: PR dotnet#33281 - Introduced in: 10.0.40 - Works in: 10.0.30, 10.0.31 - Platform: Android only ### Screenshots |Before|After| |--|--| |<img width="540" alt="image" src="https://github.com/user-attachments/assets/4c365c06-6aa9-4471-9553-d46983ec66c7" >|<img width="540" alt="image" src="https://github.com/user-attachments/assets/d67723d9-fd79-4dcc-8451-f1537f8b3668" >|
- Add android-arm64 and android-x64 test cases to PublishNativeAOT and PublishNativeAOTRootAllMauiAssemblies tests - Add PrepareNativeAotBuildPropsAndroid() with Android-specific build properties including ANDROID_NDK_ROOT support - Add ExpectedNativeAOTWarningsAndroid baseline (XA1040 + IL3050 warnings) - Use OnlyAndroid() helper on Linux to avoid iOS/macCatalyst workload issues --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…nd pixel-level comparison (dotnet#34024) <!-- 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! ### Root Cause `SafeAreaInsetsDidChange` fires repeatedly during iOS animations (e.g., `TranslateToAsync`, bottom sheet transitions) as views move relative to the window. This caused two distinct infinite loop patterns: 1. **Sub-pixel oscillation** (dotnet#32586, dotnet#33934): Animations produce sub-pixel differences in `SafeAreaInsets` (e.g., `0.0000001pt`). Exact equality fails, triggering `InvalidateAncestorsMeasures` → layout pass → position change → new `SafeAreaInsetsDidChange` → infinite loop. 2. **Parent-child double application** (dotnet#33595): A `ContentPage` (implementing `ISafeAreaView`) and its child `Grid` both independently apply safe area adjustments. When the `ContentPage` adjusts its layout for the notch/status bar, it repositions the `Grid`. The `Grid`'s new position fires `SafeAreaInsetsDidChange`, causing it to re-apply its own adjustment — creating a ping-pong loop. ### Description of Change **Primary fix — `IsParentHandlingSafeArea` (parent hierarchy walk):** In both `MauiView.ValidateSafeArea` and `MauiScrollView.ValidateSafeArea`, before applying safe area adjustments, we now check whether an ancestor `MauiView` is already applying safe area for the **same edges**. If so, the child skips its own adjustment to avoid double-padding. The check is **edge-aware**: a parent handling `Top` does not block a child from independently handling `Bottom`. Only overlapping edges cause deferral. The `_parentHandlesSafeArea` result is cached per layout cycle and cleared on `SafeAreaInsetsDidChange`, `InvalidateSafeArea`, and `MovedToWindow`. **Secondary fix — `EqualsAtPixelLevel`:** Safe area values are compared at device-pixel resolution (rounding to `1 / ContentScaleFactor`) before deciding whether to trigger a layout invalidation. This absorbs sub-pixel animation noise and prevents the oscillation loops in dotnet#32586 and dotnet#33934. **MauiScrollView bug fixes:** - Inverted condition: `!UpdateContentInsetAdjustmentBehavior()` was incorrectly gating behavior; corrected to `UpdateContentInsetAdjustmentBehavior()`. - The `_appliesSafeAreaAdjustments` flag now correctly incorporates `!IsParentHandlingSafeArea()`. **What was removed:** - The "Window Guard" approach (comparing `Window.SafeAreaInsets` to filter noise) was tried and removed. It was fragile: on macCatalyst with a custom TitleBar, `WindowViewController` repositions content by pushing it down, which changes the view's own `SafeAreaInsets` without changing `Window.SafeAreaInsets`. The guard blocked this legitimate change, causing a 28px content shift regression in CI. ### Issues Fixed Fixes dotnet#32586 Fixes dotnet#33934 Fixes dotnet#33595 Fixes dotnet#34042 --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Tamilarasan-Paranthaman <Tamilarasan-Paranthaman@users.noreply.github.com>
Replace deprecated ShowTextAtPoint with CTLine/NSAttributedString for text rendering on iOS. Fix HorizontalAlignment offset direction to match Android (subtract width for Right/Center alignment). Fixes dotnet#24450 Fixes dotnet#8486 Fixes dotnet#4993 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
This PR fixes a long-standing bug (reported as early as 2021) where ICanvas.DrawString with a HorizontalAlignment parameter was not rendering text on iOS and macOS/MacCatalyst. The root cause was that the old implementation used the deprecated CGContext.ShowTextAtPoint API, which had known rendering issues on these platforms.
Changes:
- Replaces the deprecated
ShowTextAtPointCoreGraphics API with a modern CoreText-based rendering pipeline (CTLine+CTStringAttributes) - Refactors the alignment offset logic to eliminate duplicated
DrawStringcalls by computing the offset first and then calling through to a single drawing path - Adds a UI regression test (HostApp page + NUnit test) for issue #8486
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/Graphics/src/Graphics/Platforms/MaciOS/PlatformCanvas.cs |
Replaces deprecated text rendering API with CoreText-based rendering; cleans up alignment branching |
src/Controls/tests/TestCases.HostApp/Issues/Issue8486.cs |
New HostApp test page demonstrating DrawString with all three horizontal alignments |
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue8486.cs |
New NUnit screenshot-based UI test verifying text renders correctly |
| namespace Maui.Controls.Sample.Issues | ||
| { | ||
|
|
||
| [Issue(IssueTracker.Github, 8486, "GraphicsView DrawString not rendering in iOS", PlatformAffected.iOS)] |
There was a problem hiding this comment.
The [Issue] attribute on Issue8486.cs specifies PlatformAffected.iOS, but GitHub issues #8486, #24450, and #4993 all report the bug as affecting both iOS and macOS/MacCatalyst. The fix in PlatformCanvas.cs is shared code (under MaciOS) that applies to both platforms. Consider using PlatformAffected.iOS | PlatformAffected.MacCatalyst or PlatformAffected.All to accurately reflect the affected platforms.
| var font = new CTFont((_font?.ToCGFont() ?? FontExtensions.GetDefaultCGFont()).FullName, _fontSize); | ||
| _context.TextMatrix = CGAffineTransform.MakeIdentity(); | ||
| _context.ScaleCTM(1, -1f); | ||
| _context.TranslateCTM(x, -y); | ||
| _context.SetFillColor(_fontColor); | ||
| _context.SetFont(_font?.ToCGFont() ?? FontExtensions.GetDefaultCGFont()); | ||
| _context.SetFontSize(_fontSize); | ||
| _context.SetTextDrawingMode(CGTextDrawingMode.Fill); | ||
| _context.TextMatrix = FlipTransform; | ||
| #pragma warning disable BI1234 // Type or member is obsolete | ||
| #pragma warning disable CA1422, CA1416 // Validate platform compatibility | ||
| _context.ShowTextAtPoint(x, y, value); | ||
| #pragma warning restore CA1422 // Validate platform compatibility | ||
| #pragma warning restore BI1234, CA1416 // Type or member is obsolete | ||
| var attributedString = new NSAttributedString(value, new CTStringAttributes { ForegroundColorFromContext = true, Font = font }); | ||
|
|
||
| using (var textLine = new CTLine(attributedString)) | ||
| textLine.Draw(_context); |
There was a problem hiding this comment.
Line 1009 creates a CTFont through an unnecessarily indirect path: _font?.ToCGFont() (or FontExtensions.GetDefaultCGFont()) creates an intermediate CGFont object that is immediately discarded after .FullName is extracted. This CGFont is never disposed, creating a native resource leak on every call to DrawString. The existing FontExtensions.ToCTFont() and GetDefaultCTFont() methods (which are already used at line 1101 in the same file) can create the CTFont directly without this intermediate step.
Additionally, the CTFont (font) created on line 1009 and the NSAttributedString (attributedString) created on line 1014 are never disposed. The established pattern in this file explicitly disposes such objects (see DrawStringInPlatformPath at lines 1174-1175 and DrawAttributedText at lines 1259-1260). Since DrawString may be called frequently (e.g., during animation redraws), these leaks can accumulate meaningfully.
Suggested approach: use _font?.ToCTFont(_fontSize) ?? FontExtensions.GetDefaultCTFont(_fontSize) for the font, and dispose both font and attributedString after the CTLine.Draw() call.
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
Add visual test snapshots for DrawStringShouldDrawText across platforms. Adds PNG fixtures for Android, macOS, and iOS (including ios-26) under the TestCases snapshots to support UI/visual regression testing.
🤖 AI Summary📊 Expand Full Review🔍 Pre-Flight — Context & Validation📝 Review Session — Update PlatformCanvas.cs ·
|
| File | Type |
|---|---|
src/Graphics/src/Graphics/Platforms/MaciOS/PlatformCanvas.cs |
Fix |
src/Controls/tests/TestCases.HostApp/Issues/Issue8486.cs |
Test (HostApp) |
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue8486.cs |
Test (NUnit) |
| Snapshot images (ios, ios-26, android, mac) | Test baselines |
Remaining Open Issues
| File:Line | Concern | Status |
|---|---|---|
Issue8486.cs:4 |
PlatformAffected.iOS should be PlatformAffected.iOS | PlatformAffected.MacCatalyst since fix is in shared MaciOS OPEN |
code |
| PR comments (riccardominato) | Other DrawString overloads and DrawText may have similar issues with bounding rect from canvas.GetStringSize() |
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #26304 | Replace deprecated ShowTextAtPoint with CTLine/NSAttributedString CoreText rendering; proper resource disposal via ` PENDING (Gate) |
PlatformCanvas.cs (+10/-19 net in latest state) |
Original improved after prior review | PR using` |
🚦 Gate — Test Verification
📝 Review Session — Update PlatformCanvas.cs · e21d2f4
Result PASSED:
Platform: ios
Mode: Full Verification (RequireFullVerification: true)
- Tests FAIL without fix (bug confirmed present when fix reverted)
- Tests PASS with fix (fix confirmed working)
Test: DrawStringShouldDrawText in Issue8486
Merge Base: 6c123d7
Current HEAD: e21d2f4 ("Update PlatformCanvas. resource disposal improvements)cs"
The Gate confirms the latest commit (e21d2f4) still passes: resource disposal improvements did not break the fix.
🔧 Fix — Analysis & Comparison
📝 Review Session — Update PlatformCanvas.cs · e21d2f4
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| A (prior) | try-fix | UIKit NSAttributedString.DrawString(CGPoint) via UIGraphics.PushContext PASS | PlatformCanvas.cs |
Requires platform #if more complex | branching |
| CTLine + TextMatrix PASS | PlatformCanvas.cs |
Unnecessary CTTypesetter wrapping | |||
| C (prior) | try-fix | CTFramesetter path (DrawStringInPlatformPath FAIL | PlatformCanvas.cs |
6.42% visual alignment mismatch | diff routing) |
| D (prior) | try-fix | Offscreen CGBitmapContext FAIL | PlatformCanvas.cs |
7-8% visual antialiasing mismatch | diff blit |
| 1 | try-fix (claude-sonnet-4.6) | CTFont Glyph-Path Fill via GetPathForGlyph per FAIL | PlatformCanvas.cs |
3.67% visual non-CTLine antialiasing | diff character |
| 2 | try-fix (claude-opus-4.6) | CTLine + SaveState + CTM TranslateCTM+ScaleCTM PASS | PlatformCanvas.cs |
Clean isolation; slightly more code | |
| 3 | try-fix (gpt-5.2) | CTLine + TextPosition + FlipTransform + SaveState/RestoreState PASS | PlatformCanvas.cs |
Uses existing FlipTransform; more explicit state | |
| 4 | try-fix (gpt-5.3-codex) | CTLine + TextPosition + FlipTransform (no SaveState PASS | PlatformCanvas.cs |
Minimal diff vs PR; TextMatrix not used for position | ) |
| 5 | try-fix (gemini-3-pro-preview) | CTLine + SaveState + FlipTransform with Tx/Ty mutation PASS | PlatformCanvas.cs |
Reuses FlipTransform field; state isolated | |
| 6 | try-fix (claude-sonnet-4.6) | CTLine unified: GetTypographicBounds() for alignment, no private DrawString PASS | PlatformCanvas.cs |
5.94% diff vs existing PR snapshot regen required | snapshots |
| PR | PR #26304 | CTLine + TextMatrix(1,0,0,-1,x,y) + proper disposal for font/attributedString/textLine PASS (Gate) | PlatformCanvas.cs (+10/-19) |
Original resource leaks fixed in commit e21d2f4 | PR |
Cross-Pollination Summary
| Round | Model | Response |
|---|---|---|
| Ran as Attempt 6 | ||
| 2 | claude-opus-4.6 | NO NEW IDEAS |
| 2 | gpt-5.2 | NEW IDEA: Explicit font rendering flags (not a bug fix) |
| 2 | gpt-5.3-codex | NEW IDEA: Pixel-snapping (minor refinement, not tested) |
| 2 | gemini-3-pro-preview | NEW IDEA: TextKit/NSLayoutManager (far too complex) |
| 3 | claude-sonnet-4.6 | NEW IDEA: UIGraphics.PushContext (already done as Attempt A) |
| 3 | claude-opus-4.6 | NO NEW IDEAS |
| 3 | gpt-5.2 | NEW IDEA: CGContext rendering flags (not a bug fix) |
| 3 | gpt-5.3-codex | NO NEW IDEAS |
| 3 | gemini-3-pro-preview | NO NEW IDEAS |
Exhausted: Yes (max 3 rounds reached; remaining "new ideas" are either already tried or refinements/non-fixes)
Key Finding: Only CTLine.Draw()-based approaches produce pixel-identical output to baseline snapshots. All non-CTLine methods (glyph path fill, CTFramesetter, CGBitmapContext) produce 3-8% visual diffs due to antialiasing differences. Among CTLine variants, the PR's approach (TextMatrix encoding position+flip) is the minimal, clean solution.
Selected Fix: PR's Correct and minimal; resource leaks already addressed by author in commit e21d2f41fix
Rationale: The PR's approach is the minimal correct implementation: CTLine.Draw() with a single TextMatrix that encodes both the Y-flip and translation. All resource objects are properly disposed via using var. Attempt 6 (GetTypographicBounds) is a valid refinement but requires regenerating all 4 snapshot images due to sub-pixel metric differences between UIFont (used by GetStringSize) and CTFont (used by GetTypographicBounds). This additional churn is not justified given the PR already passes.
📋 Report — Final Recommendation
📝 Review Session — Update PlatformCanvas.cs · e21d2f4
Final Recommendation: REQUEST CHANGES##
Summary
This PR fixes a long-standing bug (#8486, #24450, #4993) where ICanvas.DrawString(value, x, y, horizontalAlignment) silently failed to render text in GraphicsView on iOS and macOS/MacCatalyst. The root cause and fix approach are correct. The author has addressed the resource management issues from the prior agent review (commit e21d2f4). Two minor items remain before merge.
Root Cause
The private DrawString(string, float, float) method in PlatformCanvas.cs used CGContext. a deprecated CoreGraphics API that silently fails to render on modern Apple platforms. The Core Graphics coordinate system is y-up (flipped vs UIKit's y-down), requiring explicit coordinate transform setup with the replacement API.ShowTextAtPoint
Fix Quality
The current PR implementation (after commit e21d2f4) is correct and clean:
private void DrawString(string value, float x, float y)
{
using var font = _font?.ToCTFont(_fontSize) ?? FontExtensions.GetDefaultCTFont(_fontSize);
var attributes = new CTStringAttributes { Font = font, ForegroundColor = _fontColor.AsCGColor() };
using var attributedString = new NSAttributedString(value, attributes);
using var textLine = new CTLine(attributedString);
_context.TextMatrix = new CGAffineTransform(1, 0, 0, -1, x, y);
textLine.Draw(_context);
}Previously requested changes (now fixed):
- CTFont no longer created via intermediate uses
ToCTFont(_fontSize)directlyCGFont - CTFont properly disposed via
using var - NSAttributedString properly disposed via
using var
Multi-model try-fix exploration confirmed the PR's approach is optimal: 10+ alternative approaches were tested across 3 rounds; all CTLine.Draw()-based variants pass, all non-CTLine approaches produce 3-8% visual diffs vs existing baseline snapshots. No alternative was found that is both simpler and requires no snapshot regeneration.
Remaining Issues
**
- Missing NOTE block in PR All PRs must include the NOTE block at the top of the description per repository policy:description
> [!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!
**
2. PlatformAffected.iOS should include PlatformAffected.MacCatalyst in Issue8486.cs line The fix is in Platforms/MaciOS/PlatformCanvas.cs, shared code that compiles for both iOS and MacCatalyst. Issues #4993 and #24450 explicitly report the bug on macCatalyst. The test attribute should reflect this:4
// Change from:
[Issue(IssueTracker.Github, 8486, "GraphicsView DrawString not rendering in iOS", PlatformAffected.iOS)]
// To:
[Issue(IssueTracker.Github, 8486, "GraphicsView DrawString not rendering in iOS", PlatformAffected.iOS | PlatformAffected.MacCatalyst)]Technical Notes for Future Reference
- Only
CTLine.Draw()produces pixel-identical output to the established snapshot baselines. All alternative rendering pipelines (CTFramesetter, glyph-path fill, CGBitmapContext blit) produce visible antialiasing differences. - The alignment width from
GetStringSize()(UIFont metrics) vsCTLine.GetTypographicBounds()(CTFont metrics) can differ at sub-pixel level. The PR's approach (GetStringSize for alignment, CTLine for drawing) is consistent with existing codebase patterns and the snapshot baselines were captured with this approach. - Other
DrawStringoverloads (with bounding rect) andDrawTextmay have similar issues when used withcanvas. tracked separately in issue comments, not part of this PR's scope.GetStringSize()
Verdict
The fix is technically sound and the author has been responsive to feedback. Once the NOTE block is added to the PR description and PlatformAffected is updated to include MacCatalyst, this PR is ready to merge.
📋 Expand PR Finalization Review
Title: ✅ Good
Current: [iOS] GraphicsView DrawString - fix
Description: ❌ Needs Rewrite
Description needs updates. See details below.
✨ Suggested PR Description
[!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!
Root Cause
PlatformCanvas.DrawString(string, float, float) on iOS/MacCatalyst used the deprecated Quartz 2D API CGContext.ShowTextAtPoint() to render text. This API is obsolete and no longer renders text correctly on modern iOS. The code was working around the deprecation warnings with #pragma warning disable BI1234 / CA1422 / CA1416 suppression, masking the underlying problem.
Description of Change
Replaces the deprecated Quartz text rendering with the Core Text (CTLine) API in the private DrawString(string value, float x, float y) method in PlatformCanvas.cs:
Before (broken on iOS):
_context.SetFillColor(_fontColor);
_context.SetFont(_font?.ToCGFont() ?? FontExtensions.GetDefaultCGFont());
_context.SetFontSize(_fontSize);
_context.SetTextDrawingMode(CGTextDrawingMode.Fill);
_context.TextMatrix = FlipTransform;
#pragma warning disable BI1234, CA1422, CA1416
_context.ShowTextAtPoint(x, y, value); // ← deprecated, broken
#pragma warning restore BI1234, CA1422, CA1416After (correct Core Text rendering):
using var font = _font?.ToCTFont(_fontSize) ?? FontExtensions.GetDefaultCTFont(_fontSize);
var attributes = new CTStringAttributes { Font = font, ForegroundColor = _fontColor.AsCGColor() };
using var attributedString = new NSAttributedString(value, attributes);
using var textLine = new CTLine(attributedString);
_context.TextMatrix = new CGAffineTransform(1, 0, 0, -1, x, y); // position + Y-flip in one matrix
textLine.Draw(_context);Also simplifies the DrawString(string, float, float, HorizontalAlignment) overload by removing the redundant Left-alignment branch (x is adjusted in-place for Right/Center; Left falls through unchanged to the unconditional DrawString call at the end).
Before / After
| Before | After |
|---|---|
![]() |
![]() |
Key Technical Details
Why ShowTextAtPoint broke:
CGContext.ShowTextAtPointis part of the old Quartz 2D text subsystem, deprecated in favor of Core Text- Core Text (
CTLine) uses attributed strings and correctly handles font metrics, rendering mode, and coordinate transforms
Why TextMatrix must embed position:
CTLine.Draw()uses the context'sTextMatrixto determine where to draw- Setting
TextMatrix = new CGAffineTransform(1, 0, 0, -1, x, y)simultaneously sets position (x, y) and Y-axis flip (the-1on the diagonal), which is required because iOS graphics contexts have a flipped coordinate system relative to Core Text
Failed approaches (for future agents):
See below.
What NOT to Do (for future agents)
- ❌ Don't use
CGContext.ShowTextAtPoint— deprecated, does not render text correctly on modern iOS; covered by#pragma warning disable BI1234 / CA1422 / CA1416 - ❌ Don't use
CTFramesetter— adds framing overhead and failed visual regression checks in earlier fix attempts for this issue - ❌ Don't use Glyph Paths approach — also failed visual regression checks in earlier fix attempts
Issues Fixed
Fixes #24450
Fixes #8486
Fixes #4993
Platforms Tested
- iOS
- Android
- Mac (MacCatalyst)
- Windows
Code Review: ✅ Passed
Code Review — PR #26304
File reviewed: src/Graphics/src/Graphics/Platforms/MaciOS/PlatformCanvas.cs
New files: Issue8486.cs (HostApp + SharedTests), snapshot images
✅ Looks Good
1. Correct API replacement
Replacing CGContext.ShowTextAtPoint with CTLine.Draw is the right approach. The old API is deprecated and broken on modern iOS. Core Text (CTLine) is the proper replacement.
2. Proper using disposal
CTFont, NSAttributedString, and CTLine are all disposed via using. This matches the existing pattern in the file (see DrawStringInPlatformPath at line ~1170) and prevents native object leaks.
3. TextMatrix with embedded position
_context.TextMatrix = new CGAffineTransform(1, 0, 0, -1, x, y) correctly encodes both the drawing position and the Y-axis flip needed for Core Text in iOS's flipped graphics context. This is the established pattern.
4. Code simplification in the alignment overload
Removing the Left-alignment branch and calling DrawString(value, x, y) unconditionally at the end is a clean simplification. Left alignment needs no x adjustment; Right and Center adjust x in-place. Functionally equivalent but less code.
5. Snapshot images on all platforms
Snapshots provided for Android, iOS (14/15), iOS-26, and Mac — good cross-platform coverage for this visual fix.
🟡 Suggestions
1. CGColor from AsCGColor() not disposed
// PlatformCanvas.cs, line 1008
var attributes = new CTStringAttributes { Font = font, ForegroundColor = _fontColor.AsCGColor() };AsCGColor() allocates a new CGColor object. CTStringAttributes is a struct and not IDisposable, so the returned CGColor cannot easily be disposed here inline. However, looking at the existing patterns in the same file (e.g., _context.SetStrokeColor(StandardColors.Blue.AsCGColor()) at line 1044), this is consistent with the rest of the codebase. The impact is minor (short-lived allocation during drawing), but for strict resource hygiene a local variable could be used:
// Suggested improvement (minor, not blocking)
using var cgColor = _fontColor.AsCGColor();
var attributes = new CTStringAttributes { Font = font, ForegroundColor = cgColor };Note: This is optional. CGColor objects are typically small and collected quickly by the GC. The existing codebase does not dispose them inline either.
2. Missing newline at end of both new Issue8486.cs files
Both new files end with \ No newline at end of file:
src/Controls/tests/TestCases.HostApp/Issues/Issue8486.cssrc/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue8486.cs
This is a minor style issue. A trailing newline should be added to conform with standard C# file conventions.
3. PlatformAffected.iOS on the HostApp test page
// Issue8486.cs (HostApp)
[Issue(IssueTracker.Github, 8486, "GraphicsView DrawString not rendering in iOS", PlatformAffected.iOS)]The fix is in PlatformCanvas.cs which is in the MaciOS platform folder — it applies to both iOS and MacCatalyst. The test also includes a Mac snapshot (DrawStringShouldDrawText.png in TestCases.Mac.Tests). Consider PlatformAffected.iOS | PlatformAffected.macOS to accurately reflect scope. Minor — not blocking.
ℹ️ Informational (Out of Scope for this PR)
GetStringSize() usage for alignment
The alignment overload still calls GetStringSize(value, _font, _fontSize) to measure text width before adjusting x. A reviewer (@riccardominato) noted this relates to issue #18679, which reports potential measurement inaccuracies. This is pre-existing behavior not introduced by this PR, and is a separate concern. Worth tracking but not a blocker here.
Other DrawString overloads not addressed
The same reviewer noted that the DrawString(string, float, float, float, float, ...) overload (with bounding box) and DrawText may have related issues when combined with GetStringSize. This PR only fixes the simple DrawString(string, float, float, HorizontalAlignment) path. Fixing additional overloads is out of scope for this PR but worth filing a follow-up issue.
### Issues Fixed Fixes #24450 Fixes #8486 Fixes #4993 |Before|After| |--|--| |<img src="https://github.com/user-attachments/assets/c7fc942b-4f51-4892-8756-5bd09ae5a74d" width="300px"/>|<img src="https://github.com/user-attachments/assets/8d9f9144-9144-4585-9786-9ffa8033363e" width="300px"/>|
### Issues Fixed Fixes #24450 Fixes #8486 Fixes #4993 |Before|After| |--|--| |<img src="https://github.com/user-attachments/assets/c7fc942b-4f51-4892-8756-5bd09ae5a74d" width="300px"/>|<img src="https://github.com/user-attachments/assets/8d9f9144-9144-4585-9786-9ffa8033363e" width="300px"/>|
### Issues Fixed Fixes #24450 Fixes #8486 Fixes #4993 |Before|After| |--|--| |<img src="https://github.com/user-attachments/assets/c7fc942b-4f51-4892-8756-5bd09ae5a74d" width="300px"/>|<img src="https://github.com/user-attachments/assets/8d9f9144-9144-4585-9786-9ffa8033363e" width="300px"/>|
### Issues Fixed Fixes #24450 Fixes #8486 Fixes #4993 |Before|After| |--|--| |<img src="https://github.com/user-attachments/assets/c7fc942b-4f51-4892-8756-5bd09ae5a74d" width="300px"/>|<img src="https://github.com/user-attachments/assets/8d9f9144-9144-4585-9786-9ffa8033363e" width="300px"/>|
### Issues Fixed Fixes #24450 Fixes #8486 Fixes #4993 |Before|After| |--|--| |<img src="https://github.com/user-attachments/assets/c7fc942b-4f51-4892-8756-5bd09ae5a74d" width="300px"/>|<img src="https://github.com/user-attachments/assets/8d9f9144-9144-4585-9786-9ffa8033363e" width="300px"/>|
## What's Coming .NET MAUI inflight/candidate introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 66 commits with various improvements, bug fixes, and enhancements. ## Activityindicator - [Android] Implemented material3 support for ActivityIndicator by @Dhivya-SF4094 in #33481 <details> <summary>🔧 Fixes</summary> - [Implement material3 support for ActivityIndicator](#33479) </details> - [iOS] Fix: ActivityIndicator IsRunning ignores IsVisible when set to true by @bhavanesh2001 in #28983 <details> <summary>🔧 Fixes</summary> - [[iOS] [ActivityIndicator] `IsRunning` ignores `IsVisible` when set to `true`](#28968) </details> ## Button - [iOS] Button RTL text and image overlap - fix by @kubaflo in #29041 ## Checkbox - [iOS/MacCatalyst] Fix CheckBox foreground color not resetting when set to null by @Ahamed-Ali in #34284 <details> <summary>🔧 Fixes</summary> - [[iOS] Color of the checkBox control is not properly worked on dynamic scenarios](#34278) </details> ## CollectionView - [iOS] Fix: CollectionView does not clear selection when SelectedItem is set to null by @Tamilarasan-Paranthaman in #30420 <details> <summary>🔧 Fixes</summary> - [CollectionView not being able to remove selected item highlight on iOS](#30363) - [[MAUI] Select items traces are preserved](#26187) </details> - [iOS] CV2 ItemsLayout update by @kubaflo in #28675 <details> <summary>🔧 Fixes</summary> - [CollectionView CollectionViewHandler2 doesnt change ItemsLayout on DataTrigger](#28656) - [iOS CollectionView doesn't respect a change to ItemsLayout when using Items2.CollectionViewHandler2](#31259) </details> - [iOS][CV2] Fix CollectionView renders large empty space at bottom of view by @devanathan-vaithiyanathan in #31215 <details> <summary>🔧 Fixes</summary> - [[iOS] [MacCatalyst] CollectionView renders large empty space at bottom of view](#17799) - [[iOS/Mac] CollectionView2 EmptyView takes up large horizontal space even when the content is small](#33201) </details> - [iOS] Fixed issue where group Header/Footer template was set to all items when IsGrouped was true for an ObservableCollection by @Tamilarasan-Paranthaman in #29144 <details> <summary>🔧 Fixes</summary> - [[iOS] Group Header/Footer Repeated for All Items When IsGrouped is True for ObservableCollection in CollectionView](#29141) </details> - [Android] Fix CollectionView selection crash with HeaderTemplate by @NirmalKumarYuvaraj in #34275 <details> <summary>🔧 Fixes</summary> - [[Bug] [Android] System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index](#34247) </details> ## DateTimePicker - [iOS] Fix TimePicker AM/PM frequently changes when the app is closed and reopened by @devanathan-vaithiyanathan in #31066 <details> <summary>🔧 Fixes</summary> - [[iOS] TimePicker AM/PM frequently changes when the app is closed and reopened](#30837) - [Maui 10 iOS TimePicker Strange Characters in place of AM/PM](#33722) </details> - Android TimePicker ignores 24 hour system setting when using Format Property - fix by @kubaflo in #28797 <details> <summary>🔧 Fixes</summary> - [Android TimePicker ignores 24 hour system setting when using Format Property](#28784) </details> ## Drawing - [iOS, Mac, Windows] GraphicsView: Fix Background/BackgroundColor not updating by @NirmalKumarYuvaraj in #31254 <details> <summary>🔧 Fixes</summary> - [[iOS, Mac, Windows] GraphicsView does not change the Background/BackgroundColor](#31239) </details> - [iOS] GraphicsView DrawString - fix by @kubaflo in #26304 <details> <summary>🔧 Fixes</summary> - [DrawString not rendering in iOS.](#24450) - [GraphicsView DrawString not rendering in iOS](#8486) - [DrawString doesn't work on maccatalyst](#4993) </details> - [Android] - Fix Shadow Rendering For Transparent Fill, Stroke (Lines), and Text on Shapes by @prakashKannanSf3972 in #29528 <details> <summary>🔧 Fixes</summary> - [Ellipse Transparency Not Rendered When Drawing Arc Inside the Ellipse Using GraphicsView on Android](#29394) </details> - Revert "[iOS, Mac, Windows] GraphicsView: Fix Background/BackgroundColor not updating (#31254)" by @Ahamed-Ali via @Copilot in #34508 ## Entry - [iOS 26] Fix Entry MaxLength not enforced due to new multi-range delegate by @kubaflo in #32045 <details> <summary>🔧 Fixes</summary> - [iOS 26 - The MaxLength property value is not respected on an Entry control.](#32016) - [.NET MAUI Entry Maximum Length not working on iOS and macOS](#33316) </details> - [iOS] Fixed Entry with IsPassword toggling loses previously entered text by @SubhikshaSf4851 in #30572 <details> <summary>🔧 Fixes</summary> - [Entry with IsPassword toggling loses previously entered text on iOS when IsPassword is re-enabled](#30085) </details> ## Essentials - Fix for FilePicker PickMultipleAsync nullable reference type by @SuthiYuvaraj in #33163 <details> <summary>🔧 Fixes</summary> - [FilePicker PickMultipleAsync nullable reference type](#33114) </details> - Replace deprecated NetworkReachability with NWPathMonitor on iOS/macOS by @jfversluis via @Copilot in #32354 <details> <summary>🔧 Fixes</summary> - [NetworkReachability is obsolete on iOS/maccatalyst 17.4+](#32312) - [Use NWPathMonitor on iOS for Essentials Connectivity](#2574) </details> ## Essentials Connectivity - Update Android Connectivity implementation to use modern APIs by @jfversluis via @Copilot in #30348 <details> <summary>🔧 Fixes</summary> - [Update the Android Connectivity implementation to user modern APIs](#30347) </details> ## Flyout - [iOS] Fixed Flyout icon not updating when root page changes using InsertPageBefore by @Vignesh-SF3580 in #29924 <details> <summary>🔧 Fixes</summary> - [[iOS] Flyout icon not replaced by back button when root page is changed using InsertPageBefore](#29921) </details> ## Flyoutpage - [iOS] Flyout Items Not Displayed in RightToLeft FlowDirection in Landscape - fix by @kubaflo in #26762 <details> <summary>🔧 Fixes</summary> - [Flyout Items Not Displayed in RightToLeft FlowDirection on iOS in Landscape Orientation and Hamburger Icon Positioned Incorrectly](#26726) </details> ## Image - [Android] Implemented Material3 support for Image by @Dhivya-SF4094 in #33661 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for Image](#33660) </details> ## Keyboard - [iOS] Fix gap at top of view after rotating device while Entry keyboard is visible by @praveenkumarkarunanithi in #34328 <details> <summary>🔧 Fixes</summary> - [Focusing and entering texts on entry control causes a gap at the top after rotating simulator.](#33407) </details> ## Label - [Android] Support for images inside HTML label by @kubaflo in #21679 <details> <summary>🔧 Fixes</summary> - [Label with HTML TextType does not display images on Android](#21044) </details> - [fix] ContentLabel Moved to a nested class to prevent CS0122 in external source generators by @SubhikshaSf4851 in #34514 <details> <summary>🔧 Fixes</summary> - [[MAUI] Building Maui App with sample content results CS0122 errors.](#34512) </details> ## Layout - Optimize ordering of children in Flex layout by @symbiogenesis in #21961 - [Android] Fix control size properties not available during Loaded event by @Vignesh-SF3580 in #31590 <details> <summary>🔧 Fixes</summary> - [CollectionView on Android does not provide height, width, logical children once loaded, works fine on Windows](#14364) - [Control's Loaded event invokes before calling its measure override method.](#14160) </details> ## Mediapicker - [iOS/Android] MediaPicker: Fix image orientation when RotateImage=true by @michalpobuta in #33892 <details> <summary>🔧 Fixes</summary> - [MediaPicker.PickPhotosAsync does not preserve image orientation](#32650) </details> ## Modal - [Windows] Fix modal page keyboard focus not shifting to newly opened modal by @jfversluis in #34212 <details> <summary>🔧 Fixes</summary> - [Keyboard focus does not shift to a newly opened modal page: Pressing enter clicks the button on the page beneath the modal page](#22938) </details> ## Navigation - [iOS26] Apply view margins in title view by @kubaflo in #32205 <details> <summary>🔧 Fixes</summary> - [NavigationPage TitleView iOS 26](#32200) </details> - [iOS] System.NullReferenceException at NavigationRenderer.SetStatusBarStyle() by @kubaflo in #29564 <details> <summary>🔧 Fixes</summary> - [System.NullReferenceException at NavigationRenderer.SetStatusBarStyle()](#29535) </details> - [iOS 26] Fix back button color not applied for NavigationPage by @Shalini-Ashokan in #34326 <details> <summary>🔧 Fixes</summary> - [[iOS] Color not applied to the Back button text or image on iOS 26](#33966) </details> ## Picker - Fix Picker layout on Mac Catalyst 26+ by @kubaflo in #33146 <details> <summary>🔧 Fixes</summary> - [[MacOS 26] Text on picker options are not centered on macOS 26.1](#33229) </details> ## Progressbar - [Android] Implemented Material3 support for ProgressBar by @SyedAbdulAzeemSF4852 in #33926 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for Progressbar](#33925) </details> ## RadioButton - [iOS, Mac] Fix for RadioButton TextColor for plain Content not working by @HarishwaranVijayakumar in #31940 <details> <summary>🔧 Fixes</summary> - [RadioButton: TextColor for plain Content not working on iOS](#18011) </details> - [All Platforms] Fix RadioButton warning when ControlTemplate is set with View content by @kubaflo in #33839 <details> <summary>🔧 Fixes</summary> - [Seeking clarification on RadioButton + ControlTemplate + Content documentation](#33829) </details> - Visual state change for disabled RadioButton by @kubaflo in #23471 <details> <summary>🔧 Fixes</summary> - [RadioButton disabled UI issue - iOS](#18668) </details> ## SafeArea - [Android] Fix for TabbedPage BottomNavigation BarBackgroundColor not extending to system navigation bar by @praveenkumarkarunanithi in #33428 <details> <summary>🔧 Fixes</summary> - [[Android] TabbedPage BottomNavigation BarBackgroundColor does not extend to system navigation bar area in Edge-to-Edge mode](#33344) </details> ## ScrollView - [Android] ScrollView: Fix HorizontalScrollBarVisibility not updating immediately at runtime by @SubhikshaSf4851 in #33528 <details> <summary>🔧 Fixes</summary> - [Runtime Scrollbar visibility not updating correctly on Android and macOS platforms.](#33400) </details> - Fixed crash when calling ItemsView.ScrollTo on unloaded CollectionView by @kubaflo in #25444 <details> <summary>🔧 Fixes</summary> - [App crashes when calling ItemsView.ScrollTo on unloaded CollectionView](#23014) </details> ## Shell - [Shell] Update logic for iOS large title display in ShellItemRenderer by @kubaflo in #33246 - [iOS][Shell] Fix navigation lifecycle and back button for More tab (>5 tabs) by @kubaflo in #27932 <details> <summary>🔧 Fixes</summary> - [OnAppearing and OnNavigatedTo does not work when using extended Tabbar (tabbar with more than 5 tabs) on IOS.](#27799) - [Shell.BackButtonBehavior does not work when using extended Tabbar (tabbar with more than 5 tabs)on IOS.](#27800) - [Shell TabBar More button causes ViewModel command binding disconnection on back navigation](#30862) - [Content page onappearing not firing if tabs are on the more tab on IOS](#31166) </details> - [iOS 26] Fix tab bar ghosting when navigating from modal to tabbed Shell content by @SubhikshaSf4851 in #34254 <details> <summary>🔧 Fixes</summary> - [[iOS] Tab bar ghosting issue on iOS 26 (liquid glass)](#34143) </details> - Fix for Shell tab visibility not updating when navigating back multiple pages by @BagavathiPerumal in #34403 <details> <summary>🔧 Fixes</summary> - [Changing Shell Tab Visibility when navigating back multiple pages ignores Shell Tab Visibility](#33351) </details> - [iOS/Mac] Fixed OnBackButtonPressed not firing for Shell Navigation Bar Button by @Dhivya-SF4094 in #34401 <details> <summary>🔧 Fixes</summary> - [[iOS] OnBackButtonPressed not firing for Shell Navigation Bar button](#34190) </details> ## Slider - [iOS] Fix for Slider ThumbImageSource is not centered properly on iOS 26 by @HarishwaranVijayakumar in #34019 <details> <summary>🔧 Fixes</summary> - [[iOS 26] Slider ThumbImageSource is not centered properly](#33967) </details> - [Android] Fix improper rendering of ThumbimageSource in Slider by @NirmalKumarYuvaraj in #34064 <details> <summary>🔧 Fixes</summary> - [[Slider] MAUI Slider thumb image is big on android](#13258) </details> ## Stepper - [iOS] Fix Stepper layout overlap in landscape on iOS 26 by @Vignesh-SF3580 in #34325 <details> <summary>🔧 Fixes</summary> - [[.NET10] D10 - Customize cursor position - Rotating simulator makes the button and label overlap](#34273) </details> ## SwipeView - [iOS] SwipeView: Honor FontImageSource.Color in SwipeItem icon by @kubaflo in #27389 <details> <summary>🔧 Fixes</summary> - [[iOS] SwipeView: SwipeItem.IconImageSource.FontImageSource color value not honored](#27377) </details> ## Switch - [Android] Fix Switch thumb shadow missing when ThumbColor is set by @Shalini-Ashokan in #33960 <details> <summary>🔧 Fixes</summary> - [Android Switch Control Thumb Shadow](#19676) </details> ## Toolbar - [iOS/Mac Catalyst 26] Fix Shell.ForegroundColor not applied to ToolbarItems by @SyedAbdulAzeemSF4852 in #34085 <details> <summary>🔧 Fixes</summary> - [[iOS26] Shell.ForegroundColor is not applied to ToolbarItems](#34083) </details> - [Android] VoiceOver on Toolbar Item by @kubaflo in #29596 <details> <summary>🔧 Fixes</summary> - [VoiceOver on Toolbar Item](#29573) - [SemanticProperties do not work on ToolbarItems](#23623) </details> <details> <summary>🧪 Testing (11)</summary> - [Testing] Additional Feature Matrix Test Cases for CollectionView by @TamilarasanSF4853 in #32432 - [Testing] Feature Matrix UITest Cases for VisualStateManager by @LogishaSelvarajSF4525 in #34146 - [Testing] Feature Matrix UITest Cases for Clip by @TamilarasanSF4853 in #34121 - [Testing] Feature matrix UITest Cases for Map Control by @HarishKumarSF4517 in #31656 - [Testing] Feature matrix UITest Cases for Visual Transform Control by @HarishKumarSF4517 in #32799 - [Testing] Feature Matrix UITest Cases for Shell Pages by @NafeelaNazhir in #33945 - [Testing] Feature Matrix UITest Cases for Triggers by @HarishKumarSF4517 in #34152 - [Testing] Refactoring Feature Matrix UITest Cases for CheckBox Control by @LogishaSelvarajSF4525 in #34283 - Resolve UI test Build Sample failures - Candidate March 16 by @Ahamed-Ali in #34442 - Fix the failures in the Candidate branch- March 16 by @Ahamed-Ali in #34453 <details> <summary>🔧 Fixes</summary> - [March 16th, Candidate](#34437) </details> - Fixed the iOS 18.5 Candidate failures (March 16,2026) by @Ahamed-Ali in #34593 <details> <summary>🔧 Fixes</summary> - [March 16th, Candidate](#34437) </details> </details> <details> <summary>📦 Other (2)</summary> - Fixed candidate test failures caused by PR #33428. by @Ahamed-Ali in #34515 <details> <summary>🔧 Fixes</summary> - [[.NET10] On Android, there's a big space at the top for I, M and N2 & N3](#34509) </details> - Revert "[iOS] Button RTL text and image overlap - fix (#29041)" in b0497af </details> <details> <summary>📝 Issue References</summary> Fixes #2574, Fixes #4993, Fixes #8486, Fixes #13258, Fixes #14160, Fixes #14364, Fixes #17799, Fixes #18011, Fixes #18668, Fixes #19676, Fixes #21044, Fixes #22938, Fixes #23014, Fixes #23623, Fixes #24450, Fixes #26187, Fixes #26726, Fixes #27377, Fixes #27799, Fixes #27800, Fixes #28656, Fixes #28784, Fixes #28968, Fixes #29141, Fixes #29394, Fixes #29535, Fixes #29573, Fixes #29921, Fixes #30085, Fixes #30347, Fixes #30363, Fixes #30837, Fixes #30862, Fixes #31166, Fixes #31239, Fixes #31259, Fixes #32016, Fixes #32200, Fixes #32312, Fixes #32650, Fixes #33114, Fixes #33201, Fixes #33229, Fixes #33316, Fixes #33344, Fixes #33351, Fixes #33400, Fixes #33407, Fixes #33479, Fixes #33660, Fixes #33722, Fixes #33829, Fixes #33925, Fixes #33966, Fixes #33967, Fixes #34083, Fixes #34143, Fixes #34190, Fixes #34247, Fixes #34273, Fixes #34278, Fixes #34437, Fixes #34509, Fixes #34512 </details> **Full Changelog**: main...inflight/candidate
### Issues Fixed Fixes dotnet#24450 Fixes dotnet#8486 Fixes dotnet#4993 |Before|After| |--|--| |<img src="https://github.com/user-attachments/assets/c7fc942b-4f51-4892-8756-5bd09ae5a74d" width="300px"/>|<img src="https://github.com/user-attachments/assets/8d9f9144-9144-4585-9786-9ffa8033363e" width="300px"/>|



Issues Fixed
Fixes #24450
Fixes #8486
Fixes #4993