Skip to content

June 8th, Candidate - #35716

Merged
PureWeen merged 175 commits into
mainfrom
inflight/candidate
Jul 6, 2026
Merged

June 8th, Candidate#35716
PureWeen merged 175 commits into
mainfrom
inflight/candidate

Conversation

@PureWeen

@PureWeen PureWeen commented Jun 2, 2026

Copy link
Copy Markdown
Member

What's Coming

.NET MAUI inflight/candidate introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 175 commits with various improvements, bug fixes, and enhancements.

Activityindicator

Animation

API

Blazor

Border

Button

CollectionView

🔧 Fixes

Core

Core Lifecycle

Datepicker

DateTimePicker

Docs

Drawing

Editor

Entry

Essentials

Essentials Texttospeech

Flyoutpage

Gestures

Hybridwebview

Image

Label

Layout

Listview

Map

Menubar

Navigation

Navigationpage

Picker

Progressbar

RadioButton

Refreshview

SafeArea

ScrollView

Searchbar

SearchBar

Shell

Slider

Stepper

SwipeView

🔧 Fixes

Switch

🔧 Fixes

TabbedPage

🔧 Fixes

Templates

Toolbar

Tooling

WebView

Window

Xaml

🔧 Infrastructure (3)
🧪 Testing (3)
🏠 Housekeeping (1)
📦 Other (12)
📝 Issue References

Fixes #4131, Fixes #4715, Fixes #5947, Fixes #7150, Fixes #7814, Fixes #7935, Fixes #8296, Fixes #9095, Fixes #9150, Fixes #10041, Fixes #12669, Fixes #13258, Fixes #14708, Fixes #15257, Fixes #16470, Fixes #17175, Fixes #17554, Fixes #17698, Fixes #18021, Fixes #18055, Fixes #18238, Fixes #19542, Fixes #19668, Fixes #20502, Fixes #20615, Fixes #21562, Fixes #22053, Fixes #23074, Fixes #24752, Fixes #27101, Fixes #27627, Fixes #27770, Fixes #27922, Fixes #28514, Fixes #28676, Fixes #28891, Fixes #29411, Fixes #29449, Fixes #30010, Fixes #30046, Fixes #30404, Fixes #30464, Fixes #30535, Fixes #30957, Fixes #31048, Fixes #31177, Fixes #31472, Fixes #31686, Fixes #32279, Fixes #32393, Fixes #32404, Fixes #32457, Fixes #32476, Fixes #32492, Fixes #32731, Fixes #32871, Fixes #33508, Fixes #33510, Fixes #33780, Fixes #34038, Fixes #34104, Fixes #34257, Fixes #34380, Fixes #34522, Fixes #34558, Fixes #34584, Fixes #34594, Fixes #34634, Fixes #34823, Fixes #34830, Fixes #34832, Fixes #34899, Fixes #34930, Fixes #34955, Fixes #34971, Fixes #34973, Fixes #34993, Fixes #35060, Fixes #35076, Fixes #35088, Fixes #35103, Fixes #35107, Fixes #35113, Fixes #35114, Fixes #35147, Fixes #35180, Fixes #35183, Fixes #35211, Fixes #35214, Fixes #35244, Fixes #35249, Fixes #35257, Fixes #35277, Fixes #35279, Fixes #35280, Fixes #35286, Fixes #35293, Fixes #35313, Fixes #35326, Fixes #35331, Fixes #35344, Fixes #35354, Fixes #35371, Fixes #35380, Fixes #35381, Fixes #35387, Fixes #35390, Fixes #35396, Fixes #35397, Fixes #35399, Fixes #35401, Fixes #35405, Fixes #35416, Fixes #35429, Fixes #35469, Fixes #35472, Fixes #35473, Fixes #35479, Fixes #35481, Fixes #35483, Fixes #35485, Fixes #35492, Fixes #35495, Fixes #35497, Fixes #35498, Fixes #35513, Fixes #35517, Fixes #35568, Fixes #35573, Fixes #35574, Fixes #35584, Fixes #35587, Fixes #35615, Fixes #35618, Fixes #35651, Fixes #35654, Fixes #35696

Full Changelog: main...inflight/candidate

KarthikRajaKalaimani and others added 30 commits June 2, 2026 14:33
)

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

### Issue Details:

Horizontalspacing / Verticalspacing is not not applied to the first
column in GridItemLayout using CollectionView on Android platform.
        
### Root Cause:

The grid spacing was not being distributed symmetrically across the
active layout implementations, so edge items did not fully participate
when spacing changed at runtime.

### Description of Change:

- On Android, the fix in MauiRecyclerView.cs changes how RecyclerView
padding is handled for GridItemsLayout. Android was already using
SpacingItemDecoration, which applies half-spacing on all four sides of
each item. Previously, negative RecyclerView padding canceled that
spacing at the control edges. The branch keeps that negative-padding
behavior for non-grid layouts, but disables it for GridItemsLayout,
allowing the grid’s half-spacing to remain visible at the outer
perimeter. This makes the first row and first column visually respond
when spacing changes, but it also changes the grid behavior from spacing
only between items to spacing around the outside edges as well.

**Tested the behavior in the following platforms:**

- [x] Android
- [x] Windows
- [ ] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #34257      

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/578dda69-1d60-474c-a6d8-23b3f9d29a50"
Width="300" Height="600"> | <Video
src="https://github.com/user-attachments/assets/7f3826e6-5922-4b6f-a6b9-de581b7db6c3"
Width="300" Height="600"> |
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

<!-- Enter description of the fix in this section -->
This pull request standardizes the namespace declarations for several
test case files related to issues in the test suite. The changes ensure
that all files use the correct `Microsoft.Maui.TestCases.Tests.Issues`
namespace, improving consistency and maintainability.

**Namespace corrections:**

* Changed the namespace in `Issue22075.cs` from
`Microsoft.Maui.TestCases.Tests.Issue` to
`Microsoft.Maui.TestCases.Tests.Issues` to match the naming convention.
* Updated the namespace in `Issue28968.cs` from
`Microsoft.Maui.TestCases.Tests.Tests.Issues` to
`Microsoft.Maui.TestCases.Tests.Issues`.
* Updated the namespace in `Issue29588.cs` from
`Microsoft.Maui.TestCases.Tests.Tests.Issues` to
`Microsoft.Maui.TestCases.Tests.Issues`.
* Changed the namespace in `Issue33227.cs` from
`Maui.Controls.TestCases.Tests.Issues` to
`Microsoft.Maui.TestCases.Tests.Issues`.
…35092)

<!-- Please keep the note below for people who 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 whether this change resolves your
issue. Thank you!<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

This pull request addresses an issue where the `WebView` rendered blank
when both a `HybridWebView` and a regular `WebView` coexisted in the
same Windows (UWP) app. The main fix ensures that `HybridWebView` only
creates a custom `CoreWebView2Environment` if custom settings are
provided, allowing both controls to share the default environment and
preventing conflicts. Additionally, new test cases have been added to
verify the fix.
### Description of Change
**Bug fix for WebView and HybridWebView coexistence:**

* Updated `HybridWebViewHandler.Windows.cs` so that a custom
`CoreWebView2Environment` is created only if the user provides custom
settings; otherwise, the default shared environment is used. This
prevents conflicts when both `HybridWebView` and `WebView` are present
in the same app, resolving the blank rendering issue.
[[1]](diffhunk://#diff-9adaedb7571e93283664d8e3db8d34930d748bbe1207eb004f53e25e08eaaaeaR310-R325)
[[2]](diffhunk://#diff-9adaedb7571e93283664d8e3db8d34930d748bbe1207eb004f53e25e08eaaaeaR337-R341)

**Test coverage improvements:**

* Added a new UI test in
`TestCases.Shared.Tests/Tests/Issues/Issue34558.cs` to verify that the
regular `WebView` renders content successfully when coexisting with a
`HybridWebView`.
* Introduced a new test case page in
`TestCases.HostApp/Issues/Issue34558.cs` that sets up both controls and
provides UI elements for automated verification.



<!-- Enter description of the fix in this section -->

### Issues Fixed

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

Fixes #34558 
### Tested the behavior in the following platforms

- [x] Windows
- [ ] Android
- [ ] iOS
- [ ] Mac

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/4ba3435a-99af-4e7e-82be-6dbb588e07b6">
| <video
src="https://github.com/user-attachments/assets/fb5b1e22-b317-4421-829c-0f9b15c84e77">
|
<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
…PI changes) (#35095)

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

Enables third-party platform backends (for example Maui.Gtk) to provide
their own `DisplayAlertAsync` / `DisplayActionSheetAsync` /
`DisplayPromptAsync` implementations without MAUI exposing any new
public API. This complements #33267: because that PR introduces a new
public interface, it must wait for .NET 11. This PR solves the same
problem using already-shipped public argument types, so it is shippable
in .NET 10.

`AlertManager.Subscribe()` now keeps the existing explicit internal
`IAlertManagerSubscription` path, then checks for keyed delegate
registrations before falling back to the platform default. The delegate
signatures use only existing public types:

```csharp
Func<Page, AlertArguments,       Task<bool>>
Func<Page, ActionSheetArguments, Task<string>>
Func<Page, PromptArguments,      Task<string>>
```

The registrations are keyed so MAUI does not accidentally consume
unrelated `Func<>` services:

| Dialog | Service key |
|---|---|
| Alert | `Microsoft.Maui.Controls.DisplayAlert` |
| Action sheet | `Microsoft.Maui.Controls.DisplayActionSheet` |
| Prompt | `Microsoft.Maui.Controls.DisplayPrompt` |

Consumer usage:

```csharp
builder.Services.AddKeyedSingleton<Func<Page, AlertArguments, Task<bool>>>(
    "Microsoft.Maui.Controls.DisplayAlert",
    async (page, args) =>
    {
        return await MyGtkDialog.ShowAsync(args.Title, args.Message, args.Accept, args.Cancel);
    });
```

If any keyed delegate is registered, MAUI wraps it in a new internal
`DelegateAlertSubscription`. Registered operations dispatch to their
delegate; unregistered operations fall through to the platform default.
The delegate returns the dialog result and MAUI completes the
corresponding `AlertArguments`, `ActionSheetArguments`, or
`PromptArguments` internally. If the delegate returns `null`, faults, or
cancels, the caller observes that through the original `Display*Async`
task instead of hanging silently.

Precedence order in `Subscribe()`:

1. Explicit `IAlertManagerSubscription` service (existing internal path,
unchanged)
2. Keyed result-returning delegate convention (new)
3. Platform default subscription (existing fallback)

### Notes for reviewers

- Zero public API surface: no `PublicAPI.*.txt` changes. The new
`DelegateAlertSubscription` class and key constants are internal;
consumers use literal string keys documented on the existing argument
types.
- Keyed registrations are intentional. Unkeyed `Func<>` services are
ignored to avoid accidental collisions.
- The delegate returns the dialog result instead of calling
`args.SetResult(...)`. This matches the built-in async platform pattern
where MAUI completes the argument after awaiting the native dialog
result.
- Per-operation fall-through is intentional. A backend can override just
alerts and keep the platform action sheet/prompt, for example.
- `OnPageBusy` is excluded from the convention (obsolete in .NET 10,
removed in .NET 11) and always routes to the fallback.
- When .NET 11 ships a proper public
`IAlertManager`/`IAlertDialogProvider`, this delegate convention can
stay as a lightweight alias or be deprecated. Either way, .NET 10
consumers are unblocked now.

### Tests

Unit coverage in `AlertManagerTests.cs` includes:

- Alert, action sheet, and prompt delegate dispatch
- Returned delegate results completing the original `Display*Async`
caller
- Unregistered operation fall-through
- Unkeyed delegate services being ignored
- Explicit `IAlertManagerSubscription` precedence
- Synchronous and asynchronous delegate faults
- Delegate cancellation forwarding
- Null task contract violation

Focused `AlertManagerTests` pass locally: 21/21.

### Issues Fixed

Fixes #34104

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…ing ToPlatform and subsequent property changes (#31159)

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

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

- The iOS Label performance was improved in PR #30864. In that PR, the
Label and Entry Feature Matrix test sample and script were modified,
which caused discrepancies in the expected images due to changes which
is due to test sample's default property values. In this PR, I updated
the test sample and re-saved the images accordingly.

- Windows - The Entry is now unfocused, so I re-saved the latest image.
- Android - I modified the test sample by altering the default values
and re-saved two images.

Additionally, while working on the test sample changes, I identified and
fixed issues in FormattedStringExtensions.

These updates improve formatted text rendering on iOS by correctly
propagating span properties (font, character spacing, and line-break
settings) from the label to each span. The layout logic is also more
robust, falling back to MAUI’s calculated size when iOS has not yet
provided a valid label size, preventing incorrect text positioning and
rendering issues.

### Issues Fixed

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

Contributing to #30864

---------

Co-authored-by: KarthikRajaKalaimani <92777139+KarthikRajaKalaimani@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <kubaflo123@gmail.com>
Co-authored-by: albyrock87 <albyrock87@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# Conflicts:
#	src/Controls/tests/TestCases.HostApp/Issues/Issue34671.cs
The Visual Studio signing scan flags unsigned files inside MAUI workload
pack MSIs. This PR adds signing configuration for two categories of
unsigned files:

### 1. Unsigned `.cab` files (75 files across 75 payloads)

Every MAUI workload pack MSI contains an embedded `cab1.cab.cab` cabinet
archive that is currently unsigned. This affects 69 `maui*` payloads and
6 `aspnetcorewebviewmaui*` payloads across net9.0/net10.0 ×
arm64/x64/x86.

**Fix:** Add `FileExtensionSignInfo` for `.cab` with `Microsoft400`
(which Arcade auto-converts to `MicrosoftDotNet500` since
`UseDotNetCertificate` is `true`).

**Affected payloads (cab):**
- `mauicontrols{10020100200,90120901200}{arm64,x64,x86}`
- `mauicontrolsbuildtasks{10020100200,90120901200}{arm64,x64,x86}`
- `mauicontrolscompatibility90120901200{arm64,x64,x86}`
- `mauicontrolscore{10020100200,90120901200}{arm64,x64,x86}`
- `mauicontrolsxaml{10020100200,90120901200}{arm64,x64,x86}`
- `mauicore{10020100200,90120901200}{arm64,x64,x86}`
- `mauiessentials{10020100200,90120901200}{arm64,x64,x86}`
- `mauigraphics{10020100200,90120901200}{arm64,x64,x86}`
- `mauigraphicswindows{10020100200,90120901200}{arm64,x64,x86}`
- `mauiresizetizer{10020100200,90120901200}{arm64,x64,x86}`
- `mauisdknet{10,9}{10020100200,90120901200}{arm64,x64,x86}`
- `mauitemplatesnet{10,9}{10020100200,90120901200}{arm64,x64,x86}`
- `aspnetcorewebviewmaui{10020100200,90120901200}{arm64,x64,x86}`

### 2. Unsigned `ReconnectModal.razor.js` (3 files)

The Blazor reconnect modal script from
`Microsoft.AspNetCore.Components.Web` is packed into
`mauitemplatesnet10` workload MSIs without a signature.

**Fix:** Add `FileSignInfo` for `ReconnectModal.razor.js` with
`Microsoft400`.

**Affected payloads (js):**
- `mauitemplatesnet1010020100200{arm64,x64,x86}`
…latform (#35179)

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

### Issue Details:

DragGestureRecognizer.DropCompleted event not firing in Android platform
       
### Root Cause:

DragAndDropGestureHandler.SetupHandlerForDrop() only called
SetOnDragListener(this) when the view had a DropGestureRecognizer. On
Android, DragAction.Ended is only delivered to views that have a drag
listener registered. A view with only a DragGestureRecognizer (no
DropGestureRecognizer) never registered a listener → never received
DragAction.Ended → HandleDropCompleted never called → DropCompleted
event never fired.

### Description of Change:

The fix is in
src/Controls/src/Core/Platform/Android/DragAndDropGestureHandler.cs.
Modified the listener registration for drag-source-only views (those
with no DropGestureRecognizer) is now done just before
StartDragAndDrop() is called, scoping it to the active drag and
preventing sibling views in the same layout from accidentally becoming
drag listeners. In the DragAction.Ended handler, the fix always
dispatches DropCompleted to the tracked dragSourceElement regardless of
which view received the event — since on Android, DragAction.Ended can
arrive on a non-source view first. A one-shot DropCompletedSent flag on
the local drag state prevents the event from firing more than once. Once
the source view receives DragAction.Ended, the temporary listener is
unregistered to restore the original state.

**Tested the behavior in the following platforms: **

- [x] Android
- [ ] Windows
- [ ] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #17554          

### Screenshots
| Before  | After  |
|---------|--------|
| <Video width="300" height="600"
src="https://github.com/user-attachments/assets/243dec05-a560-4d26-87dd-cb6e8b99ab27"
/> | <Video width="300" height="600"
src="https://github.com/user-attachments/assets/3137deb3-4f45-476e-8e96-15661609c546"
/> |
- ICrossPlatformLayout.CrossPlatformArrange can call LayoutButton with a
null button so it should be prepared for that.

Fixes #31048

---------
…35086)

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

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


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
TabbedPage tab titles get truncated on Android when there are more than
3 tabs (e.g., "New Tab 1" shows as "N..."). Tabs should scroll
horizontally and show full titles.

### Root Cause
TabbedPageManager.cs creates the Android TabLayout with TabMode =
TabLayout.ModeFixed, which divides screen width equally among all tabs.

### Description of Change
Changed TabMode from ModeFixed to ModeScrollable in which sizes tabs to
fit their content and enables horizontal scrolling.
 

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #16470 

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/1e984577-08aa-4091-b1fc-53bac5511154"
>| <video
src="https://github.com/user-attachments/assets/8c3ef77b-5d1a-480c-8e33-c3f485d04b53">|
…ebViewHandler in AddControlsHandlers (#34868)

`AOTTemplateTest.PublishNativeAOT` and
`PublishNativeAOTRootAllMauiAssemblies` fail on Android NativeAOT
because the Android ILC (SDK 36.99.0-preview.3.10) emits unexpected
`IL3050` warnings for `HybridWebViewHandler` constructors—despite the
call site already being correctly guarded by a
`[FeatureGuard]`-annotated feature switch.

## Why the warnings appear

`HybridWebViewHandler` carries
`[RequiresDynamicCode]`/`[RequiresUnreferencedCode]` because it uses
dynamic `System.Text.Json` serialization. The registration in
`AddControlsHandlers` is inside a proper feature guard:

```csharp
// RuntimeFeature.IsHybridWebViewSupported has:
//   [FeatureGuard(typeof(RequiresDynamicCodeAttribute))]
//   [FeatureGuard(typeof(RequiresUnreferencedCodeAttribute))]
// MauiHybridWebViewSupported=false is set by MSBuild targets when PublishAot=true
if (RuntimeFeature.IsHybridWebViewSupported)
{
    handlersCollection.AddHandler<HybridWebView, HybridWebViewHandler>();
}
```

The iOS/macCatalyst NativeAOT ILC correctly honors `[FeatureGuard]` and
suppresses the warnings. The Android NativeAOT ILC does not, so
`IL3050`/`IL2026` leak through and break the test's strict
warning-baseline check.

## Fix

Explicitly suppress with `#pragma` at the affected call site—the same
pattern used elsewhere in the codebase (`ResourceDictionaryHelpers.cs`,
etc.) for ILC warnings on code that is provably safe via a feature
guard:

```csharp
if (RuntimeFeature.IsHybridWebViewSupported)
{
    // NOTE: not registered under NativeAOT or TrimMode=Full scenarios.
    // IL2026/IL3050 suppressed because IsHybridWebViewSupported has [FeatureGuard] annotations
    // for both RequiresUnreferencedCode and RequiresDynamicCode. The Android NativeAOT ILC does
    // not honor [FeatureGuard] for warning suppression (unlike iOS/macCatalyst), so suppress explicitly.
#pragma warning disable IL2026, IL3050
    handlersCollection.AddHandler<HybridWebView, HybridWebViewHandler>();
#pragma warning restore IL2026, IL3050
}
```

No baseline changes needed—the pragma suppression is respected by the
ILC so the warnings are no longer emitted.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
…ide the Border (#30408)

<!-- 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 of the issue



- On Windows, when a ContentView with a clip applied during the
SizeChanged event is placed inside a Border, both the ContentView
(through WrapperView) and the Border's content (via ContentPanel)
attempt to apply their own clips to the same visual element.

- The clip set in the ContentPanel.UpdateClip method of the Border is
applied after the WrapperView has already set its clip, resulting in the
Border overwriting the clip geometry originally applied.



### Description of Change



- The fix introduces a condition in ContentPanel.UpdateClip that checks:
- Whether the content's visual already has a clip (visual.Clip is not
null)
- Whether the content is wrapped by a WrapperView (Content.Parent is
WrapperView)
- If both conditions are met, the ContentPanel skips applying its own
clip to the content, allowing the ContentView’s clip (set by the
WrapperView) to be preserved.



### Issues Fixed



Fixes #30404 



### Tested the behaviour in the following platforms



- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac



### Screenshot



| Before Issue Fix | After Issue Fix |
|----------|----------|
| <img
src="https://github.com/user-attachments/assets/04381895-5d99-4ac8-9a2e-7d35aaa03dd4">
| <img
src="https://github.com/user-attachments/assets/04938f65-5c0a-4a4b-9676-c34c3ac30378">
|
…nt Width (#35213)

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

### Issue Details:

CollectionView's Header / Footer is not expanded to its content width in
iOS and Mac platform
       
### Root Cause:

In the iOS/MacCatalyst CollectionView2 implementation,
StructuredItemsViewController2 and GroupableItemsViewController2 both
have a GetViewForSupplementaryElement() method responsible for creating
header and footer views. When a TemplatedCell2 is dequeued as a
supplementary view, its ScrollDirection property was never set — it
silently defaulted to UICollectionViewScrollDirection.Vertical. This was
an oversight, because regular item cells in GetCell() already correctly
assigned ScrollDirection. The missing assignment fed through to
GetMeasureConstraints() in TemplatedCell2, which uses ScrollDirection to
decide how to constrain the cell during measurement: for a horizontal
grid, a Vertical direction incorrectly constrains the cell's width to
the estimated value (~30pt from LayoutFactory2) instead of leaving it
unconstrained, causing header/footer labels to be clipped to a tiny
width and become inaccessible in the UI tree.

### Description of Change:

The fix is a one-line addition in each of the two affected view
controllers, mirroring the pattern already used in GetCell(). In
StructuredItemsViewController2.GetViewForSupplementaryElement(),
templatedCell.ScrollDirection = ScrollDirection is set before calling
UpdateTemplatedSupplementaryView. The same line is added in
GroupableItemsViewController2.GetViewForSupplementaryElement() for group
header/footer cells. With ScrollDirection correctly propagated,
GetMeasureConstraints() leaves the width unconstrained for horizontal
grids, allowing headers and footers to self-size to their full content
width. Vertical layouts are unaffected since they already defaulted to
Vertical, and the change has no impact on Android or Windows as Items2
is iOS/MacCatalyst-only.

**Tested the behavior in the following platforms: **

- [ ] Android
- [ ] Windows
- [x] iOS
- [x] Mac

### Reference:

N/A

### Issues Fixed:

Fixes #35113            

### Screenshots
| Before  | After  |
|---------|--------|
| <img width="400" height="500"
src="https://github.com/user-attachments/assets/319d97f0-a4b9-4b00-bc9a-670fd44fd86f"
/> | <img width="400" height="500" alt="After_31553"
src="https://github.com/user-attachments/assets/710a0fca-0c92-48fd-a91f-697d9e0d6b86"
/> |
…ible=false (#34621)

### Description

On Android, navigating from a page with the soft keyboard (IME) open to
a page with `Shell.NavBarIsVisible="False"` causes the destination page
to initially render under the status bar and then jump into the correct
position.

This behavior is more noticeable when the destination page performs
heavier UI work, and in some cases the layout may remain incorrectly
positioned.

### Root Cause

During `ShellRenderer.SwitchFragment`, the fragment transaction is
committed while the IME is still visible. Android continues to report
IME-related `WindowInsets`, causing the new layout to be measured with
incorrect top insets.

Once the IME state stabilizes, the layout is corrected, resulting in a
visible jump.

### Fix

Dismiss the soft keyboard before performing the fragment transaction:

- Detect IME visibility using `IsSoftInputShowing`
- Call `HideSoftInput()` prior to `FragmentTransaction`

This ensures that `WindowInsets` are stable before the new layout is
measured.

### Result

- Eliminates layout jump when navigating with keyboard open
- Ensures correct layout positioning from initial render
- Improves Shell navigation consistency on Android

### Testing

Added a UI test (`Issue34584`) that:

- Opens the keyboard by focusing an `Entry`
- Navigates to a page with `Shell.NavBarIsVisible="False"`
- Verifies that content is laid out below the status bar (`Y > 0`)

Note: The test validates final layout correctness, not visual animation.

### Related Issues

- Fixes #34584
- Related to #34060
… Shell (#35072)

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

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details:
#8296 - ContentPage.OnBackButtonPressed not invoked on iOS/MacCatalyst
when the native navigation bar back button is tapped inside a
NavigationPage.

#9095 - Shell.OnBackButtonPressed not invoked when the toolbar back
button is tapped on Android and iOS Shell pages

### Root Cause
#8296
- ShouldPopItem in NavigationRenderer.cs (the
navigationBar:shouldPopItem: UIKit delegate callback) fires when the
user taps the native iOS back button.
- Previously it unconditionally set _uiRequestedPop = true and returned
true, allowing the native pop without ever notifying MAUI's page model.
As a result, ContentPage.OnBackButtonPressed was never called on iOS
when the native back button was tapped inside a NavigationPage.

#9095 -  iOS (ShellSectionRenderer.cs)
- Same issue — tracker.Value.Page?.SendBackButtonPressed() skipped the
Shell chain and went directly to the ContentPage.

### Description of change

#8296  **NavigationRenderer.cs**
- In ShouldPopItem, call NavPage?.CurrentPage?.SendBackButtonPressed()
before allowing the native pop. If it returns true (the page
handled/cancelled back navigation), reset _uiRequestedPop and return
false to prevent the native pop.

#9095 **ShellSectionRenderer.cs** (iOS Shell)

- Route through _context.Shell?.SendBackButtonPressed() instead of
tracker.Value.Page?.SendBackButtonPressed(), so the Shell back button
tap goes through the same chain as the system back button.

**Note** on _sendPopPending = false in the BackButtonBehavior command
path: On iOS 26+, _sendPopPending is set to true unconditionally at the
start of SendPop(), before any BackButtonBehavior checks. When a
BackButtonBehavior.Command executes and returns false (preventing
navigation), ViewDidDisappear never fires — so without an explicit
reset, the flag stays true permanently and silently blocks all
subsequent back presses. The _sendPopPending = false after command
execution (line 188) is therefore an intentional and necessary fix to
prevent the back button becoming permanently unresponsive after a
command-handled back press on iOS 26+.

### Test results 
#### Shell — `OnBackButtonPressed` (fixes #9095)

| Platform | Navigation | `OnBackButtonPressed` |
|---|---|---|
| iOS / MacCatalyst | `GoToAsync` | ✅ Triggered |
| Android | `GoToAsync` | ✅ Triggered (app back button and emulator back
button) |
| Windows | `GoToAsync` | ✅ Triggered |

>`OnBackButtonPressed` is triggered for both the `Shell` and the
contained `ContentPage`.


#### NavigationPage — `OnBackButtonPressed` (fixes #8296)

| Platform | Navigation | `OnBackButtonPressed` | Notes |
|---|---|---|---|
| iOS / MacCatalyst | `PushAsync` | ✅ Triggered | |
| iOS / MacCatalyst | `PushModalAsync` | — | Back button not visible in
modal navigation |
| Android | `PushAsync` | ✅ Triggered (app back button and emulator back
button) | |
| Android | `PushModalAsync` | ✅ Triggered | Called on the modal
ContentPage |
| Windows | `PushAsync` | ✅ Triggered | |
| Windows | `PushModalAsync` | — | Back button not visible in modal
navigation |

> On Android and Windows, `OnBackButtonPressed` is triggered for both
the `NavigationPage` and the contained `ContentPage`.

#### TabbedPage — `OnBackButtonPressed`

| Platform | Navigation | `OnBackButtonPressed` | Notes |
|---|---|---|---|
| iOS / MacCatalyst | `PushAsync` | ✅ Triggered | |
| iOS / MacCatalyst | `PushModalAsync` | — | Back button not visible in
modal navigation |
| Android | `PushAsync` | ✅ Triggered | |
| Android | `PushModalAsync` | ✅ Triggered | |
| Windows | `PushAsync` | ✅ Triggered | |
| Windows | `PushModalAsync` | — | Back button not visible in modal
navigation |

#### FlyoutPage — `OnBackButtonPressed`

| Platform | Navigation | `OnBackButtonPressed` | Notes |
|---|---|---|---|
| iOS / MacCatalyst | `PushAsync` | ✅ Triggered | |
| iOS / MacCatalyst | `PushModalAsync` | — | Back button not visible in
modal navigation |
| Android | `PushAsync` | ✅ Triggered | |
| Android | `PushModalAsync` | ✅ Triggered | |
| Windows | `PushAsync` | ✅ Triggered | |
| Windows | `PushModalAsync` | — | Back button not visible in modal
navigation |


### Validated the behaviour in the following platforms
- [ ] Android
- [ ] Windows
- [x] iOS
- [x] Mac

### Issue Fixes
Fixes #8296 

### Screenshots
|  | Before  | After |
|--|---------|--------|
|8296|  <video
src="https://github.com/user-attachments/assets/13887369-e9e9-42df-a2a0-db88f0e6b38f">
|   <video
src="https://github.com/user-attachments/assets/d0ccfb01-59e8-44bc-8878-54c5d0f6fb7e"> 
|
|9095 |  <video
src="https://github.com/user-attachments/assets/664e0b7f-3964-4a1b-a4f6-46b1db758b48">
|   <video
src="https://github.com/user-attachments/assets/3ff159ec-93b0-4a91-854a-ca23211ff204"> 
|

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s changed to default value (#35215)

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

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


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
On iOS/MacCatalyst, dynamically changing IndicatorView.IndicatorSize
back to the default value (6) at runtime has no visual effect —
indicators remain stuck at the previously set non-default size.

### Root Cause
The platform control has a hard-coded early return when the indicator
size equals the default value, which skips resetting the visual
transform even when indicators are currently scaled to a different size.
Additionally, the field tracking the last applied size was initialized
to -1 instead of the actual default.

### Description of Change
Replaced the hard-coded default value check with a comparison against
the last applied size, so the update is only skipped when the size is
truly unchanged. Initialized the tracking field to the default size to
correctly represent the initial state.
 

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #35214 

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/30f6d250-1a65-4061-986f-16d3940ac243"
>| <video
src="https://github.com/user-attachments/assets/759cc5af-9f5f-4d95-8b2a-262499928d0d">|
…ent) IsEnabled changed. (#31540)

### Issue Details:

The user has defined an implicit style for the BackgroundColor property
of a Grid, with the selected state value set to green. However, when the
IsEnabled property of the CollectionView's parent Grid is changed from
false to true immediately on the button click, the background color of
the currently selected item (which is also a Grid) is lost.
        
### Root Cause:

This happens because changing the IsEnabled property triggers the
ChangeVisualState() method in the base VisualElement class. As a result,
the visual state transitions to "Normal", overriding the previously
applied "Selected" state and its associated background color.

### Description of Change:

To address the issue, a selection check has been added to ensure that
the "Normal" state is not forced when the element is currently in the
"Selected" state. This change preserves the visual appearance of
selected items by preventing the "Selected" state from being overridden
during IsEnabled property changes.

**Tested the behavior in the following platforms.**

- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #20615 

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/14ead580-bb70-4779-8c6e-00c8e7e1d425"
Width="300" Height="600"> | <Video
src="https://github.com/user-attachments/assets/d5699514-40e7-417b-b0c6-d22ebc101a91"
Width="300" Height="600"> |

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

Fixed a small typo in Clipboard.shared.cs. Nothing exciting, really.

### Issues Fixed

Given that this is an extremely small typo fix only, I thought I'd just
go ahead and file a PR.

---------
<!-- Please keep the note below for people who 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 whether this change resolves your
issue. Thank you!
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

This pull request fixes a regression where LinearGradientBrush with
transparent stops rendered as opaque black boxes on Android starting in
10.0.60. The fix preserves per-stop alpha values so gradients render
correctly.

### Root Cause : 

- Introduced by #31567 (Android drawable perf), which rewrote
MauiDrawable.Android.cs to use a Java-side PlatformDrawable.
- In that refactor, calls to GetGradientData were written as
GetGradientData(1.0f), which forces every gradient stop's alpha to fully
opaque (255), overriding any Transparent stop colors defined by the
developer.
  
### Description of Change
**Bug fix: Gradient transparency on Android**

* Updated `MauiDrawable.Android.cs` so that both linear and radial
gradient paints now call `GetGradientData(null)` instead of
`GetGradientData(1.0f)`, preserving per-stop alpha values for
backgrounds and borders. This prevents gradients with transparent stops
from rendering as solid black.
[[1]](diffhunk://#diff-9962b2ab4d4a0eb4922307e668bfe7d868c4fac7919a9463a3cba1859a6de86fL115-R115)
[[2]](diffhunk://#diff-9962b2ab4d4a0eb4922307e668bfe7d868c4fac7919a9463a3cba1859a6de86fL129-R129)
[[3]](diffhunk://#diff-9962b2ab4d4a0eb4922307e668bfe7d868c4fac7919a9463a3cba1859a6de86fL250-R250)
[[4]](diffhunk://#diff-9962b2ab4d4a0eb4922307e668bfe7d868c4fac7919a9463a3cba1859a6de86fL264-R264)

**Testing: New test case and UI test**

* Added a new issue test page `Issue35280` that displays an image with a
linear gradient overlay fading from black to transparent, to visually
confirm the fix.
* Introduced a corresponding UI test in `Issue35280.cs` to verify that
the gradient overlay is rendered correctly and not as an opaque black
box.

<!-- Enter description of the fix in this section -->

### Issues Fixed

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

Fixes #35280 
### Tested the behavior in the following platforms

- [ ] Windows
- [x] Android
- [ ] iOS
- [ ] Mac

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <img width="1080" height="1920" alt="Screenshot_1777904296"
src="https://github.com/user-attachments/assets/a3ed29f1-9f85-44e7-9d4a-14e343aa8bda"
/> | <img width="1080" height="1920" alt="Screenshot_1777904172"
src="https://github.com/user-attachments/assets/c1f4be01-7af1-4e68-a36b-766ef167062f"
/> |
<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
…acing is applied (#35309)

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

### Issue Details
On iOS, when an Editor has CharacterSpacing applied through a Slider,
the Editor becomes scrollable once the content exceeds its frame size.
After rotating the device (portrait → landscape → portrait), the Editor
loses scrollability because a re-measurement cascade expands it to the
full content height.

**Regression PR:** #30629
 
### Root Cause
PR #30629 added ValidateSafeArea() to MauiView.LayoutSubviews, which
calls InvalidateConstraintsCache() during rotation. This clears the
measurement cache (_lastMeasuredSize = null), causing HasBeenMeasured()
= false and needsMeasure = true for Pages.
As a result, a full re-measurement cascade occurs, where the Editor is
measured with infinite height. SizeThatFits then returns the full
content height (for example, 134px), causing the Editor to grow to fit
its content and lose its scrollable behavior.
 
### Description of Change
Updated EditorHandler.GetDesiredSize to cap the measured height to the
current frame height when the Editor content exceeds its frame
(scrollable state).
An AllowAutoGrowth flag was added to MauiTextView so Editors using
AutoSize = TextChanges are excluded from the cap and can continue
growing to fit their content.

### Issues Fixed
Fixes #35114

### Screenshots

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/4f1b08f7-abb2-40ae-84d8-f05cd063339c">
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/42850642-087c-4198-91be-fc9b09b8dd43">
|
…ker.FocusChange (#29939)

Check if _editText is null before detaching the event.
)

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


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
VisualStateManager permanently breaks when attempting to set a control's
Style property during state transitions. When properties like IsEnabled
change, VSM automatically transitions states - but if that state
contains a Style setter, the control loses all VSM functionality and can
no longer respond to any state changes.

### Root Cause
The old code set the Style property by replacing the entire Style
object. This removed the original Style that contained the
VisualStateGroups attached property. Once the VSM attachment is lost,
the control cannot transition to other states - VSM is permanently
broken for that control.

### Description of Change
Added special handling when Setter values are Styles, using the
IStyle.Apply() and IStyle.UnApply() methods. Apply() applies the Style's
individual setters without replacing the Style property, keeping the VSM
connection intact. UnApply() properly removes the Style's setters when
the state changes, preventing conflicts between different states.

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #17175  

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/a5a2a482-73a2-4e84-a133-afacaf1c3872"
>| <video
src="https://github.com/user-attachments/assets/a1079f90-06cb-4083-8202-2517200b5346">|
…35208)

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

### Issue details
When a virtual XAML event handler is wired inside a DataTemplate (for
example, SwipeItem.Invoked) and the handler is defined in a base class
and overridden in a derived class, the app crashes in Release builds on
iOS/macOS and may also behave incorrectly on Android. This occurs due to
a bug in XamlC's IL code generator (SetPropertiesVisitor.cs), where the
ldvirtftn instruction receives the wrong vtable object (the anonymous
DataTemplate class instead of the root XAML element), causing runtime
failure with Full AOT compilation.

### Root Cause

The issue occurs because of incorrect IL generation in
SetPropertiesVisitor.ConnectEvent() when wiring a virtual event handler
inside a DataTemplate.

When XamlC compiles a DataTemplate, it generates an anonymous nested
class (e.g., <InitializeComponent>_anonXamlCDataTemplate_1) with a
LoadDataTemplate() method where event wiring happens. For virtual
handlers, XamlC must emit ldvirtftn, which requires the actual page
object as the vtable source to resolve the correct overridden method.

The bug was that the code always pushed Ldarg_0 as the vtable object.
Inside LoadDataTemplate(), Ldarg_0 is the anonymous class, not the root
page. This causes ldvirtftn to look up the virtual method on the wrong
vtable, so the override on the generic subclass is never found. On iOS
Full AOT, this causes a hard crash; on Android and Windows, the JIT
silently calls the base class method instead of the override.
 
### Description of Change

The fix involves replacing the extra Ldarg_0 push before ldvirtftn with
a Dup instruction, which reuses the delegate target object that is
already correctly loaded on the stack just above this code.

The delegate target (the root page) is already on the stack, correctly
resolved via context.Root for both the top-level and DataTemplate
contexts. Dup copies that same object for ldvirtftn, ensuring virtual
dispatch always targets the actual page's vtable, and the overridden
method on the generic subclass is found correctly on all platforms.
 
**Windows platform behavior:**
 
The issue does not occur on the Windows platform. Based on analysis,
even though Windows does not crash, the behavior before the fix was
technically undefined, as it relied on the JIT being lenient. If the
method resolution happened to pick the base class version instead of the
override, the logic would silently be incorrect without any error. The
fix makes the IL correct and explicit for all platforms.

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

### Issues Fixed

Fixes #18055

### Output

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video width="270" height="600"
src="https://github.com/user-attachments/assets/6bc99f45-7114-4ce5-9a75-d98d3c014882">
| <video width="270" height="600"
src="https://github.com/user-attachments/assets/00cd3e91-cb1b-4a9a-9df9-1a2538d2ec56">
|
…ding (#34845)

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
When set IsRefreshing = true in navigated page, refreshview is not
visible

### Root Cause
OnLoaded unsubscribed itself after firing once (refreshControl.Loaded -=
OnLoaded). So when the user navigated
back to the page, the Loaded event fired again but had no handler —
UpdateIsRefreshing() was never called, and
the refresh indicator never appeared.

### Description of Change

<!-- Enter description of the fix in this section -->
Removed Self-unsubscribe line refreshControl.Loaded -= OnLoaded so the
handler stays active across.

### Issues Fixed

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

Fixes #30535 

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

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

| Before  | After  |
|---------|--------|
| **Windows**<br> <video
src="https://github.com/user-attachments/assets/408e35ed-61ed-4ad2-9104-f08635c98af2"
width="600" height="300"> | **Windows**<br> <video
src="https://github.com/user-attachments/assets/c16e311b-44c0-4571-af71-b3fa316fbea2"
width="600" height="300"> |
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

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


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
Build fails with InvalidOperationException when using an empty (but
valid) SVG as the app icon. The SVG has width, height, and viewBox but
no drawn shapes inside.

### Root Cause
PR #33194 moved the size.IsEmpty check to run before both code paths in
DrawUnscaled, but size (from CullRect) is only needed in the downscale
path. Empty SVGs have a zero CullRect even with valid declared
dimensions, so the check incorrectly blocks the upscale path that never
uses size.

### Description of Change
Moved the size.IsEmpty check from before both branches into only the
else (downscale) branch where size is actually used. The scale >= 1 path
calls DrawPicture directly, which harmlessly draws nothing for empty
SVGs, producing a valid transparent image.
 

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #35293 

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/cf8040d6-9b0f-4867-bd4a-1713ea41d1d5"
>| <video
src="https://github.com/user-attachments/assets/97c09d5e-b2cc-4a13-b5a3-dc056dacba78">|
#32674)

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

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details:

The FlowDirection property is not being applied to the EmptyView content
within a CollectionView.

### Root Cause
FlowDirection was not applied correctly to EmptyView because
EffectiveUserInterfaceLayoutDirection
returned incorrect values, causing RTL detection logic to fail. After
using the correct
property to update the isRTL boolean, the flip logic produced inverted
visuals and did not properly
propagate FlowDirection changes.

### Description of Change

- Replaced transform-based RTL handling with proper FlowDirection
propagation using the MAUI ItemsView.FlowDirection.
- For View-based and DataTemplate-based EmptyViews, the old
transform-based RTL handling was removed. The platform view now updates
its layout direction through UpdateFlowDirection().
- For string-based EmptyViews rendered as a UILabel, the text alignment
is set to center to provide a better user experience.

### Validated the behaviour in the following platforms
- [x] Android
- [x]  Windows
- [x] iOS
- [x] Mac

### Issues Fixed:

Fixes #32404 
Fixes #34522

### Screenshots
| Before  | After |
|---------|--------|
|  <video
src="https://github.com/user-attachments/assets/6423b8a9-8861-4a11-b825-00b4efa28fbb">
|   <video
src="https://github.com/user-attachments/assets/1c851a9b-e772-45ea-8fd5-485e081e53ed"> 
|
…g background (#34997)

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

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


<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
On Android, switching from a gradient to a solid color is not worked —
the gradient persists visually.
On Windows, gradients are never applied, and setting Background to null
doesn't clear previously applied colors.

### Root Cause
On Android, BorderDrawable.SetBackground() doesn't clear the gradient
shader when switching to a solid color or null — the stale shader
persists on the underlying paint object.

On Windows,
[UpdateBackground()](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
only handled
[SolidPaint](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html),
so gradients were ignored and null backgrounds didn't trigger resource
cleanup.

### Description of Change
On Android, clear the shader via platformPaint.SetShader(null) in
BorderDrawable.SetBackground() before applying the solid color.
On Windows, use
[button.Background?.ToPlatform()](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
to handle all paint types and allow null to remove theme overrides.
Ensure
[RefreshThemeResources()](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
always executes.

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [ ] iOS
- [ ] Mac
 
### Issues Fixed
  
Fixes #34993  

### Output  ScreenShot
Android
|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/a48e6fd4-46df-443e-90bf-c2ce41b3a000"
>| <video
src="https://github.com/user-attachments/assets/575b452a-9b68-4568-a5ec-ea14acce17c4">|


Windows
|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/0b10cb79-2910-42ad-94e7-ef64283a8dc2"
>| <video
src="https://github.com/user-attachments/assets/74d41e8d-3734-4374-b7b7-b6e668234dfb">|
…Android in .NET 10 (#35295)

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

### Issue details
On Android (.NET MAUI 10), Shell toolbar colors are applied before
navigation completes during tab/page transitions, causing the current
page to briefly display the destination page’s colors. This is a
regression from .NET MAUI 9 and results in incorrect visual behavior
during navigation.

### Root Cause
The issue occurs because of the toolbar appearance update being
triggered before the tab navigation is fully completed when switching
tabs in a Shell with TabBar. During the tab change, the destination tab
colors are applied immediately while the previous tab content is still
visible on screen, which causes a brief color flash. This is especially
noticeable when different child pages use different toolbar colors. The
behavior started after an earlier change where the appearance update was
added during tab switching but executed before the section change was
committed.
 
### Description of Change
The fix involves changing the execution order so the section change is
committed first, and the appearance update happens only after the tab
switch is successfully accepted. This ensures the Shell internal state
is updated to the correct tab before applying the toolbar colors,
preventing premature color changes while the previous tab is still
visible. The update is also skipped when the tab switch is rejected or
cancelled, so colors continue to refresh correctly on every tab switch,
but now at the correct time.

### Why Tests were not added:

**Regarding the test case:** No automated test case was added for this
fix, as the issue is a brief visual color flash that occurs during the
tab-switch animation on Android and cannot be reliably captured through
the existing automated test infrastructure.
 
Screenshot-based tests cannot consistently capture the exact transition
frame where the issue occurs, and the current baseline comparison
approach is unable to accurately differentiate correct and incorrect
toolbar color timing during the animation.

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

**Regression PR:** The PR
[25870](#25870) as the primary
regression source. PR [32882](#32882)
appears to be a later overlapping change affecting Shell color timing.

The PR [25870](#25870) as the primary
regression source. PR [32882](#32882)
appears to be a later overlapping change affecting Shell color timing.

### Issues Fixed

Fixes #35060

### Output

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video width="270" height="600"
src="https://github.com/user-attachments/assets/44ea19d0-7aca-42b1-b936-506eb4609f33">
| <video width="270" height="600"
src="https://github.com/user-attachments/assets/f1c8b6b4-44b5-4f6b-9daa-988daa33b90c">
|
Appears to be unused, but trips up analyzers when investigating other
issues.

Fixes: xamarin/Xamarin.Forms#1749

---------
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details
In FlyoutPage, RTL FlowDirection is not working properly at initial and
runtime changes.

### Description of Changes
* Added an `UpdateFlowDirection` method to set the correct
`SemanticContentAttribute` on the root view, child controller views, and
navigation bar, ensuring proper mirroring for RTL layouts and correct
inheritance by child handlers.
* Updated property change handling to listen for `FlowDirection` changes
and trigger both `UpdateFlowDirection` and `UpdateLeftBarButton` when
flow direction is updated at runtime.
* Called `UpdateFlowDirection` during gesture recognizer setup to ensure
the correct flow direction is applied during initialization.

### Issues Fixed

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

Fixes #34830 

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

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

| Before  | After  |
|---------|--------|
| **iOS**<br> <video
src="https://github.com/user-attachments/assets/f9a9cc1a-3320-4e8b-9c6c-3702c585b5c2"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/7da0ba09-557f-46bd-81b7-2fed1295b61d"
width="300" height="600"> |
…dler disconnect (#35314)

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

Fixes #27101.

When a `Page` is navigated away from on Windows, the focused control's
handler is disconnected.
`ElementHandler.IElementHandler.DisconnectHandler()` (in
`src/Core/src/Handlers/Element/ElementHandler.cs`) sets `PlatformView =
null` **before** running the platform-specific disconnect chain.

On Windows, that chain calls `UpdateIsFocused(false)`
(`src/Core/src/Handlers/View/ViewHandler.Windows.cs`), which then sets
`virtualView.IsFocused = false`. That property change cascades through:

```
BindableObject.SetValue
  → OnIsFocusedPropertyChanged
    → ChangeVisualState
      → VisualStateManager.GoToState
        → Setter.Apply (e.g. background color)
          → BindableObject.SetValue (mapped property)
            → Handler.UpdateValue("Background")
              → Property mapper
                → handler.PlatformView ← throws "PlatformView cannot be null here"
```

The strongly-typed `PlatformView` accessor (`ViewHandlerOfT.cs`,
`ElementHandlerOfT.cs`) throws `InvalidOperationException("PlatformView
cannot be null here")` because we already nulled it.

### Fix

Introduce a new `Disconnecting` state on `ElementHandlerState` and set
it for the duration of `DisconnectHandler(oldPlatformView)`.
`ElementHandler.UpdateValue` short-circuits when the handler is in that
state, so property fan-outs during teardown no longer hit the mapper
(and therefore no longer touch the released platform view).

The state is restored in a `finally` block so a throwing platform
disconnect cannot leave the handler stuck in `Disconnecting`.

Logical state on the `BindableObject` itself still gets updated by VSM
setters (so reused/rebound elements remain correct — when a recycled
element is reconnected, `SetVirtualView` re-pushes all current property
values via `_mapper.UpdateProperties`).

### Why fix here, not in `VisualElement.ChangeVisualState()` (or
`Page.cs`)?

Several controls override `ChangeVisualState()` and call
`VisualStateManager.GoToState` directly, bypassing the base
implementation (`Button`, `ImageButton`, `CheckBox`, `RadioButton`,
`Switch`). Guarding in `ChangeVisualState` would miss those paths, and a
naive `Handler is null` check would also regress legitimate pre-handler
XAML init scenarios (`VisualStateGroupsPropertyChanged`,
`VisualStateGroupList.OnStatesChanged`).

`ElementHandler.UpdateValue` is the central choke point that all
property cascades flow through, so the guard there:
- covers every code path on every platform,
- still lets VSM logical state settle on the `BindableObject`,
- requires no changes in any control-specific override.

### Tests

- **Unit test**:
`Microsoft.Maui.UnitTests.AbstractViewHandlerTests.UpdateValueIsSkippedWhileHandlerIsDisconnecting`
simulates the property fan-out from inside `DisconnectHandler` and
asserts the mapper is not invoked. Verified that the test fails on the
unmodified code (mapper count goes from 0 to 1) and passes after the
fix.
- **UI test**:
`Microsoft.Maui.TestCases.Tests.Issues.Issue27101.NoCrashWhenNavigatingBackFromPageWithFocusedButton`
repeatedly navigates a `NavigationPage` containing a focused `Button`
styled with VSM (Normal/Focused/Disabled/PointerOver/Pressed) to surface
the focus race.

### Relation to #27877

This PR supersedes #27877. That PR wrapped the post-disconnect
`ChangeVisualState` call in `try { ... } catch (ObjectDisposedException)
{ }` inside `Page.cs`. Two issues with that approach:
1. The actual exception thrown is `InvalidOperationException`, not
`ObjectDisposedException`, so the catch likely never fires for the
reported scenario (matches the unanswered review feedback from MartyIX
on 2025‑05‑30).
2. Even with the right exception type, that's a band-aid: it lets the
failing call happen, swallows the symptom, and only patches one of many
code paths that could trip the same issue (any subclass that triggers a
property change during disconnect).

### Issues Fixed

Fixes #27101
Supersedes #27877

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
On Android, control device test cases are failing in the candidate PR
#35716 in CI, but it is not showing
which tests are failing. When checking locally, the
SwappingDetailPageWorksForSplitFlyoutBehavior test crashed. After
reverting PR #35372, the
SwappingDetailPageWorksForSplitFlyoutBehavior test no longer crashed. To
confirm this, the changes from PR
#35372 were reverted to identify the
cause of the failures.

**Note: Do not merge this PR**
Copilot AI review requested due to automatic review settings June 30, 2026 10:46

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.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

…e - 4 (#36227)

This PR addresses the test failures that occurred in the
inflight/candidate branch: #35716,
and includes updates to improve rendering and test stability across
platforms.

- The WebViewWithDarkTheme test fails in CI but passes locally; this is
due to a delay when taking the image in CI. So, updated the Issue 34823
test and added a new image for iOS 18.
@sheiksyedm

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@dotnet dotnet deleted a comment from github-actions Bot Jun 30, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 2 pipeline(s).
…e - 5 (#36300)

This PR addresses the test failures that occurred in the
inflight/candidate branch: #35716,
and includes updates to improve rendering and test stability across
platforms.

- MemoryLeakB42329, VerifyEmptyViewResizesWhenBoundsChange tests are
failing only in CI but pass locally. For now, the tests have been
restricted to make CI green.
Copilot AI review requested due to automatic review settings July 2, 2026 13:22

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.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@PureWeen
PureWeen merged commit dab8abc into main Jul 6, 2026
193 checks passed
@PureWeen
PureWeen deleted the inflight/candidate branch July 6, 2026 14:09
PureWeen added a commit that referenced this pull request Jul 7, 2026
…36410)

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

## Why
The release-readiness regression classifier could report a **CLOSED**
issue as an active `open-on-main` regression (Tier 2 — "wait for main
merge, then backport"). That's contradictory: an unmerged OPEN PR cannot
have closed a completed issue. It happens when a giant still-open
"Candidate" changelog PR `Fixes`-lists dozens of issues — its OPEN state
gets attributed to an already-completed issue. Real-world: issue #35615
(CLOSED/COMPLETED) surfaced under `open-on-main` in the SR9 tracker
while candidate PR #35716 was still open.

## What
`Classify-RegressionCandidate` now enforces: **never emit `open-on-main`
for a CLOSED issue.** When the aggregated best verdict is exactly
`open-on-main` and the issue is CLOSED:
1. First try the same comment-prose recovery the empty-candidate path
uses — a merged fix verifiably present on the SR wins →
`closed-fix-unlinked` (Tier 3, "no ship risk; add a closing reference
for traceability").
2. Otherwise fall to the honest `no-fix-yet` (Tier 3 for a CLOSED issue
via the existing `Get-OverallVerdict` downgrade) — the automation can't
pin a verified fix on this SR and the open candidate hasn't merged.

The shared recovery logic is extracted into a new
`Resolve-ClosedFixUnlinked` helper, called from both the
empty-`strongPrs` CLOSED path and the new guard, preserving the
fix-phrase gate, merged-on-SR gate, revert guards, and tooling-only
skips exactly.

**Strictly scoped:** only `open-on-main` + CLOSED is contradictory.
Every other verdict (`merged-on-main-no-backport`,
`backport-in-progress`, `rejected-from-sr`, `in-sr-*`,
`needs-human-review`) is unchanged even for CLOSED issues — those remain
legitimately actionable (the SR may still need the backport).
Genuinely-OPEN issues still get `open-on-main`.

## Tests
Three new unit tests in `Test-ReleaseReadiness.ps1`:
1. CLOSED issue + OPEN candidate on main + no comment fix →
`no-fix-yet`, proven non-blocking (🟢) via `Get-OverallVerdict`.
2. CLOSED issue + OPEN candidate + comment-cited merged fix on SR →
`closed-fix-unlinked` (recovery wins).
3. Regression guard: OPEN issue + OPEN candidate → stays `open-on-main`.

Full suite green (829/0).

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

---------

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
SyedAbdulAzeemSF4852 pushed a commit to SyedAbdulAzeemSF4852/maui that referenced this pull request Jul 27, 2026
…otnet#36410)

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

## Why
The release-readiness regression classifier could report a **CLOSED**
issue as an active `open-on-main` regression (Tier 2 — "wait for main
merge, then backport"). That's contradictory: an unmerged OPEN PR cannot
have closed a completed issue. It happens when a giant still-open
"Candidate" changelog PR `Fixes`-lists dozens of issues — its OPEN state
gets attributed to an already-completed issue. Real-world: issue dotnet#35615
(CLOSED/COMPLETED) surfaced under `open-on-main` in the SR9 tracker
while candidate PR dotnet#35716 was still open.

## What
`Classify-RegressionCandidate` now enforces: **never emit `open-on-main`
for a CLOSED issue.** When the aggregated best verdict is exactly
`open-on-main` and the issue is CLOSED:
1. First try the same comment-prose recovery the empty-candidate path
uses — a merged fix verifiably present on the SR wins →
`closed-fix-unlinked` (Tier 3, "no ship risk; add a closing reference
for traceability").
2. Otherwise fall to the honest `no-fix-yet` (Tier 3 for a CLOSED issue
via the existing `Get-OverallVerdict` downgrade) — the automation can't
pin a verified fix on this SR and the open candidate hasn't merged.

The shared recovery logic is extracted into a new
`Resolve-ClosedFixUnlinked` helper, called from both the
empty-`strongPrs` CLOSED path and the new guard, preserving the
fix-phrase gate, merged-on-SR gate, revert guards, and tooling-only
skips exactly.

**Strictly scoped:** only `open-on-main` + CLOSED is contradictory.
Every other verdict (`merged-on-main-no-backport`,
`backport-in-progress`, `rejected-from-sr`, `in-sr-*`,
`needs-human-review`) is unchanged even for CLOSED issues — those remain
legitimately actionable (the SR may still need the backport).
Genuinely-OPEN issues still get `open-on-main`.

## Tests
Three new unit tests in `Test-ReleaseReadiness.ps1`:
1. CLOSED issue + OPEN candidate on main + no comment fix →
`no-fix-yet`, proven non-blocking (🟢) via `Get-OverallVerdict`.
2. CLOSED issue + OPEN candidate + comment-cited merged fix on SR →
`closed-fix-unlinked` (recovery wins).
3. Regression guard: OPEN issue + OPEN candidate → stays `open-on-main`.

Full suite green (829/0).

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

---------

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment