Skip to content

March 30th, Inflight Candidate#34617

Open
PureWeen wants to merge 176 commits intomainfrom
inflight/candidate
Open

March 30th, Inflight Candidate#34617
PureWeen wants to merge 176 commits intomainfrom
inflight/candidate

Conversation

@PureWeen
Copy link
Member

No description provided.

NirmalKumarYuvaraj and others added 30 commits March 24, 2026 10:37
… a footer template is present or crashes when removing data. (#24867)

### Root Cause

- **Add** - When a CollectionView contains grouping and a footer
template, we create a new List<object> and add the footer to the list if
the footer's item template type is not an IList. This prevents events
such as CollectionChanged or INotifyCollectionChanged from being
triggered on the original collection. As a result, when a new item is
added to the collection, it is not reflected in the view.

- **Clear** - When clearing the collection and adding items at runtime,
a COM exception occurs when items are grouped. This happens because the
OnItemsVectorChanged event is triggered whenever there is a change in
the item collection, causing ListViewBase.ScrollIntoView to be called
from a background thread, which leads to the COM exception.
 
### Description of Change
 
#### Windows 

- **Add** - Reverting the changes made in PR #24205 caused the exception
. This exception occurred due to the triggering of the
TemplateCollectionChanged event, which was introduced during the
implementation of drag-and-drop functionality for the CollectionView in
PR #3768. Adding the footer to the items triggers the
TemplateCollectionChanged event, which incorrectly adds the footer as a
new item in the collection. Since the footer template is not the same
type as the items in the original collection, this results in the
exception. To resolve this, we can ignore the addition of the footer
template to the ItemsSource.
 
- **Clear** - Calling ListViewBase.ScrollIntoView in the DispatcherQueue
helps avoid exceptions and ensures synchronized updates.
Reference -
https://github.com/dotnet/maui/blob/5ceff42f4713a18516a0bffa209b0ed272e915b7/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/ListViewRenderer.cs#L628
 
Validated the behaviour in the following platforms
 
- [x] Android
- [x] Windows
- [ ] iOS
- [ ] Mac
 
iOS and Mac has issues - #17969 
 
### Issues Fixed
  
Fixes #24866 
Fixes #27302
Fixes #18481
Fixes #21791 

### Output 

#### Windows
|**Before**|**After**|
|--|--|
|<video
src="https://github.com/user-attachments/assets/2813d618-2c9d-4700-af20-8402b0779597">
| <video
src="https://github.com/user-attachments/assets/bb96519e-5a70-47a8-a872-d61ac2cf8f4f">
|
… value on iOS16+ - fix (#30733)

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

### Issues Fixed

Fixes #18669

|Before|After|
|--|--|
|<video
src="https://github.com/user-attachments/assets/1c43b0dc-a432-4107-81b5-d418e0a70a7b"
width="300px"></video>|<video
src="https://github.com/user-attachments/assets/fff7b26c-e703-4761-baa1-bf3e60f01005"
width="300px"></video>|
… fix (#29339)

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

### Issues Fixed

Fixes #20596

|Before|After|
|--|--|
|<video
src="https://github.com/user-attachments/assets/dd0ce289-bbff-453c-81ff-5306c891b14e"
width="300px"/>|<video
src="https://github.com/user-attachments/assets/8b07e943-4d38-4575-a216-e1252d12785c"
width="300px"/>|
…ft Text Selection on Editor and Entry (#30906)

<!-- 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
When selecting text from right to left, the SelectionLength property in
Entry and Editor is incorrectly reported as 0 on Android.
 
### Root Cause
On Android, when selecting text from right to left,
GetSelectedTextLength returned 0 due to incorrect handling of reverse
selection. In GetSelectionEnd, the selection length was also calculated
as 0, resulting in the selection length remaining zero even though text
was selected.
 
### Description of Change
 
Updated GetSelectedTextLength() to return the absolute difference
between SelectionStart and SelectionEnd using Math.Abs. Modified
GetSelectionEnd() to handle right-to-left selection by adjusting the end
position and correctly updating SelectionLength. This ensures consistent
behavior across selection directions and platforms.
 
### Validated the behaviour in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed:
Fixes #30782 
 
### Screenshots
| Before  | After |
|---------|--------|
|  <video
src="https://github.com/user-attachments/assets/9e6aff76-aa74-41f5-9047-e8449262b313">
|   <video
src="https://github.com/user-attachments/assets/e744b5fd-0b98-40d1-8875-e36e64021ccc"> 
|
…PopToRootAsync (#29779)

### Issue Detail
When the user inserts a page before the root and then pops the current
page using PopAsync (or pops to root using PopToRootAsync), the flyout
hamburger icon is not visible on iOS after the navigation completes.

### Root Cause
UpdateLeftBarButtonItem (which sets the flyout hamburger icon on the
ParentingViewController) was only called in the RemovePage method. The
programmatic pop paths — OnPopViewAsync, OnPopToRoot, and the
native-swipe-back path via UpdateFormsInnerNavigation — did not call it.
After a pop that results in a new root page, the flyout button was never
refreshed.

### Description of Change
Extracted the flyout-button-refresh logic from RemovePage into a new
private helper:

```
void UpdateFlyoutMenuButton(Page pageBeingRemoved = null)
{
    var parentingViewController = GetParentingViewController();
    parentingViewController?.UpdateLeftBarButtonItem(pageBeingRemoved);
}
```
Then called UpdateFlyoutMenuButton() at the end of:

- OnPopViewAsync — programmatic PopAsync()
- OnPopToRoot — programmatic PopToRootAsync()
- UpdateFormsInnerNavigation — native back-button (swipe) pop

RemovePage was refactored to use the same helper (no behavior change).

**File changed:**
src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs

**Reference:**
https://github.com/dotnet/maui/blob/main/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs#L693

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

### Issues Fixed
 
Fixes #21828

### Screenshots

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/7afc9d80-3d98-4f73-a124-dcc06c5e6d1c">
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/7d59f508-9760-44bb-9889-4bd4fcca9353">)
|
…ource loads with delay (#34424)

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

The bug is a **circular sizing dependency** specific to iOS horizontal
`CollectionView` with delayed data loading:

1. **UIKit assigns a large initial frame** (~812–1013px) to the
`CollectionView` before items load.
2. **`LayoutFactory2.CreateHorizontalList`** configures item and group
heights as `NSCollectionLayoutDimension.CreateFractionalHeight(1f)` —
items always fill 100% of the container height. This is intentional for
horizontal scroll UX.
3. Before items are realized, `CollectionViewContentSize.Width == 0` but
**`CollectionViewContentSize.Height` equals the current (large) frame
height** — a side effect of `FractionalHeight(1f)`.
4. In **`EnsureContentSizeForScrollDirection`** (CV2 /
`ItemsViewHandler2.iOS.cs`), the `Width == 0` branch correctly fetches a
desired width from `base.GetDesiredSize()` — but previously did NOT
reset `Height`, letting the large frame-derived height pass through.
5. MAUI reports this large height as the desired size → sets the frame
to that height → when items finally load, `FractionalHeight(1f)` × large
frame = items are large → height is never corrected. **The lock is
permanent.**

The same bug exists in the legacy CV1 handler (`ItemsViewController.cs`)
where `GetSize()` returned the raw `CollectionViewContentSize` without
resetting height for an empty horizontal layout.

### Description of Change
In both the CV2 (`Items2/`) and CV1 (`Items/`) iOS handler pipelines,
when a **horizontal CollectionView has `Width == 0`** (meaning no items
have been realized yet), also reset `Height = 0`. This breaks the
circular dependency by letting `MinimumHeightRequest` / `HeightRequest`
govern the initial size rather than an arbitrary frame-derived value.

**The condition `Width == 0`** is a reliable proxy for "no items
realized" because:
- A horizontal CV with any visible items will always have non-zero
content width.
- `Width == 0` uniquely occurs in the pre-items-loaded state that causes
the bug.

### Issues Fixed

Fixes #34336

### Technical Details

- **CV2 (`ItemsViewHandler2.iOS.cs`)** — When a horizontal
`CollectionView` has no items loaded yet (`Width == 0`),
`contentSize.Height` was incorrectly carrying the large UIKit-assigned
frame height. The fix also resets `Height` to zero in that case, so
`MinimumHeightRequest` / `HeightRequest` governs the initial size.

- **CV1 (`ItemsViewController.cs`)** — Same issue in the legacy handler.
A guard was added: if the layout is horizontal and `Width == 0`,
`Height` is reset to zero before the size is returned.

### Files Changed

| File | Change | Purpose |
|------|--------|---------|
| `src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs` | +8
lines | Fix CV2 (new iOS handler) circular height lock |
| `src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs` |
+15/-1 lines | Fix CV1 (legacy iOS handler) circular height lock |
| `src/Controls/tests/TestCases.HostApp/Issues/Issue34336.cs` | New file
(104 lines) | HostApp repro page: horizontal CV with 1s delayed
`ObservableCollection` load |
| `src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34336.cs`
| New file (31 lines) | NUnit UI test using `VerifyScreenshot(tolerance:
0.5)` to verify correct layout after delayed load |

### Screenshots

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/ce13c0b9-cd35-40fe-a341-bb3c634cd441">
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/49f720d6-b8ca-4520-bbe7-d579a9b43d18">)
|
<!-- 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
This pull request introduces a new Material 3-based `SearchBarHandler2`
for Android, and conditionally uses it when Material 3 is enabled. The
new handler and its supporting platform classes provide improved
integration with Material 3 design, including custom appearance, clear
button, and color handling. Several internal extension methods and
mappings are updated to support this new handler, while maintaining
compatibility with the existing handler for non-Material 3 scenarios.

**Material 3 SearchBar support for Android:**

* Added a new internal `SearchBarHandler2` class for Material 3, with a
complete set of property and command mappers, event handlers, and
platform view integration. This handler is used only when Material 3 is
enabled.
* **SearchView limitation:** Android’s SearchView is designed to open as
an expanded overlay when tapped, covering other content. It's meant to
work in combination with a collapsed search bar trigger.
* The overlay’s height and behavior cannot be customized to behave like
a persistent inline search field. This limitation is inherent to the
SearchView design.
* **Solution**: So Introduced `MauiMaterialTextInputLayout` and
`MauiMaterialTextInputEditText` platform classes to provide Material 3
styling, clear button, and selection change support for the new
SearchBar handler.
* Updated `AppHostBuilderExtensions.cs` to register `SearchBarHandler2`
conditionally for Android when Material 3 is enabled, otherwise falling
back to the original handler.

**Mapping and platform extension updates:**

* Modified SearchBar mapping logic in `SearchBar.Mapper.cs` to use the
correct handler and mapping methods based on whether Material 3 is
enabled on Android.
* Added new extension methods in `SearchViewExtensions.cs` for Material
3 SearchBar support, including updating text, background, icon colors,
and return type for the new handler.
* Added a Material 3-specific overload for `MapText` in
`SearchBar.Android.cs` for use with `SearchBarHandler2`.

**Internal API and behavior improvements:**

* Made `UpdateIsTextPredictionEnabled` and `UpdateIsSpellCheckEnabled`
extension methods internal to allow usage by the new handler.
* Improved `UpdateCursorSelection` in `EditTextExtensions.cs` to post
selection changes when the EditText is focused, preventing potential
issues with selection updates.

### Issues Fixed

Fixes #33947 

### Screenshot
| Material 2  | Material 3 |
|---------|--------|
| <img height=600 width=300
src="https://github.com/user-attachments/assets/75269b67-1b8c-4e31-a880-c86d4102c76c">
|  <img height=600 width=300
src="https://github.com/user-attachments/assets/ba76f61d-587f-4421-b782-24bfb7a74155"> 
|

---------

Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
<!-- 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 sizing of the RefreshView no longer works when the content is
wrapped inside a RefreshView. As a result, the RefreshView height is
calculated as 0.

### Root Cause
MauiSwipeRefreshLayout.OnMeasure called CrossPlatformMeasure() but
discarded the return value, never calling SetMeasuredDimension with the
correct size. Android kept height=0 from base.OnMeasure().

### Description of Change
Updated MauiSwipeRefreshLayout.OnMeasure() to correctly use the result
from CrossPlatformMeasure()
and call SetMeasuredDimension() with the resolved size. Previously, the
return value was discarded
and Android retained height=0 from base.OnMeasure().

The implementation respects MeasureSpecMode as follows:

- EXACTLY — uses the size from the measure spec (parent dictates size).
- AT_MOST — uses the full spec constraint (not the cross-platform
measure), matching Android's View.getDefaultSize() semantics. This is
intentional: SwipeRefreshLayout internally centers its spinner indicator
using getMeasuredWidth() / 2, so clamping to content size would
misposition the spinner.
- UNSPECIFIED — uses the size returned from CrossPlatformMeasure()
(content wraps naturally).

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


### Issues Fixed:
Fixes #12131

### Screenshots
| Before  | After |
|---------|--------|
| <img height=600 width=300
src="https://github.com/user-attachments/assets/6ffdfc04-fdc0-4c1a-b0fd-3f67c4744571">
|  <img height=600 width=300
src="https://github.com/user-attachments/assets/7143297a-94f2-48a8-9eca-3516ddf70491"> 
|
<!-- 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. !!!!!!!
-->
### Root Cause : 
`SendNavigatingFrom()` was called too early in `SendNavigating()`—before
the navigation stack updated. At that point, `CurrentPage` still pointed
to the source page, so the event incorrectly reported the source page as
the destination.
### Description of Change
Bug fix for navigation event:

* Updated `IShellController.UpdateCurrentState` in `Shell.cs` to fire
`SendNavigatingFrom` after the shell state is updated, ensuring
`CurrentPage` correctly reflects the destination page in the
`NavigatingFromEventArgs`. The navigation type is determined based on
the navigation source.
* Modified `SendNavigating` in `Shell.cs` to capture the current page
for later use, rather than immediately firing `SendNavigatingFrom`, so
the destination is correct when the event is triggered.

Test coverage for the fix:

* Added a new test case in `Issue34073.cs` under `TestCases.HostApp` to
demonstrate and validate the correct behavior of `OnNavigatingFrom`,
showing the destination page is now accurate.
* Added a UI test in `TestCases.Shared.Tests/Tests/Issues/Issue34073.cs`
that navigates between pages and asserts that the destination page
reported by `OnNavigatingFrom` is correct.


<!-- 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 #34073 
### Tested the behavior in the following platforms

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

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <img width="1080" height="1920" alt="BeforeFix34073"
src="https://github.com/user-attachments/assets/763e1c20-9f41-4fc2-b7d6-21261280b42a"
/> | <img width="1080" height="1920" alt="AfterFix34073"
src="https://github.com/user-attachments/assets/bc4f998e-52b7-492f-8fc5-61e2f56881a4">
|
| <img width="1125" height="2436" alt="BeforeFixiOS34073"
src="https://github.com/user-attachments/assets/fadc8294-77a8-4db2-b48f-787eb49e0f8b"
/> | <img width="1125" height="2436" alt="AfterFixiOS34073"
src="https://github.com/user-attachments/assets/237f1fbf-649a-48d2-9930-a182695cf9e9"
/> |
<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
…anges (#34416)

### Root Cause
On Android, MAUI declares `configChanges="density"` in the manifest. As
a result, when the user changes the system display size (display
density), the `Activity` is not recreated. Instead, the existing view
hierarchy remains active and `OnSizeChanged` is triggered to update the
view’s pixel dimensions.

However, `PlatformGraphicsView` initializes its internal `_scale` field
only once during construction, and the field is marked as `readonly`.
Because the `Activity` is not recreated, this value is never refreshed
after a density change.

This leads to a mismatch between two density sources:

* `GraphicsView.Width` and `GraphicsView.Height`, which rely on MAUI’s
cached display density (`s_displayDensity`) set at application startup.
* The `dirtyRect` passed into `IDrawable.Draw()`, which is calculated
using the stale `_scale` value from `PlatformGraphicsView`.

After a system display size change, these two values diverge. As a
result, the drawable’s coordinate space no longer aligns with the view’s
logical dimensions, causing rendering inconsistencies and incorrect
drawing behavior.

### Description of Change
Removed the `readonly` modifier from the `_scale` field in
`PlatformGraphicsView` and introduced an internal virtual
`GetDisplayDensity()` method. The `_scale` value is now refreshed on
every `OnSizeChanged` call using the value returned by this method,
ensuring it reflects the current display density.

`PlatformTouchGraphicsView` (the MAUI-integrated subclass in the Core
project) overrides `GetDisplayDensity()` to return MAUI’s cached display
density — the same value used by `GraphicsView.Width` and
`GraphicsView.Height`.

This ensures that both logical sizing and `dirtyRect` calculations rely
on a consistent density source, keeping them fully synchronized even
after a system display density change.

### Issues Fixed
Fixes #34211 
 
Tested the behaviour in the following platforms
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

### Note
display density can be forced on Android using `adb shell wm density`.
Other platforms do not provide a comparable runtime command or
automation method to override display density, so this scenario cannot
be triggered or validated the same way outside Android.

### Output Video
Before Issue Fix | After Issue Fix |
|----------|----------|
|<video width="40" height="60" alt="Before Fix"
src="https://github.com/user-attachments/assets/6c6af647-c758-40b3-802c-000d5021a936">|<video
width="50" height="40" alt="After Fix"
src="https://github.com/user-attachments/assets/85f7b299-2349-4fef-a2c1-b68b485dbd34">|
…WebView and HybridWebView (#30653)

<!-- 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
FlowDirection was only applied to the WebView and HybridWebview, not its
internal ScrollView, which handles the actual content layout and
scrolling.

### Description of Change

<!-- Enter description of the fix in this section -->
FlowDirection is now applied to the internal ScrollView of WKWebView to
ensure correct layout direction.

### 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 #30605 

### Regarding Test case
For this case, it's not possible to write a test because the scrollbar
does not appear during initial loading. It only becomes visible when a
scroll action is performed, and even then, it remains visible only for a
few seconds.

<!--
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/eaf6620b-5f00-402c-b191-2ba881cacac2"
width="300" height="600"> | **iOS**<br> <video
src="https://github.com/user-attachments/assets/b038125e-5dbf-483b-aa7d-640f2c72555e"
width="300" height="600"> |
#33439)

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->
### Issue Details
MediaPicker on Android was appending _rotated and _processed suffixes to
filenames when rotating or compressing images, causing the original
filename to be lost.

### Description of Change

<!-- Enter description of the fix in this section -->
The updated implementation closes the input stream before performing any
file operations, deletes the original file, and writes the processed
(rotated) image back to the same file path. This ensures that the
original filename is preserved, avoiding the addition of any _rotated or
_processed suffixes.

### 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 #33258 

### Regarding test case
Picking an image is not possible in a test.

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

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

| Before  | After  |
|---------|--------|
| **Android**<br> <video
src="https://github.com/user-attachments/assets/35cb8242-9d10-4926-81b8-d28e291a56fe"
width="300" height="600"> | **Android**<br> <video
src="https://github.com/user-attachments/assets/92249ba3-76af-4d05-a789-8f63d02de86b"
width="300" height="600"> |
…iew (#34382)

### Root Cause
When `RefreshView` initializes on iOS, it attaches the native
`UIRefreshControl` to the CollectionView’s scroll layer. This attachment
triggers an internal layout pass. During that layout pass, iOS
temporarily reports an incorrect container width to the layout engine,
typically double the actual screen width.
`UICollectionViewCompositionalLayout`, which is used by the CV2 handler,
uses this incorrect width to calculate the total content size and caches
it. After the animation settles and the correct screen width is
restored, the layout engine does not recalculate the content size and
continues using the cached double-width value.
As a result, the scroll system believes the content is wider than the
screen and enables horizontal scrolling.
 
### Description of Change
The fix was implemented by overriding the `CollectionViewContentSize`
property inside `CustomUICollectionViewCompositionalLayout`. This
property is where the scroll system queries the layout for the total
content size.
The override intercepts the content size before it is returned to the
scroll system. If the layout is vertical and the reported content width
is greater than the actual screen width, the width is clamped to the
real screen width before being returned.
By ensuring that a vertical layout never reports a content width larger
than the screen, horizontal scrolling is prevented.
The change is minimal, localized to a single file, and safe because a
vertical layout can never legitimately have content wider than the
screen.

### Issues Fixed
Fixes #34165 
 
Tested the behaviour in the following platforms
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

### Output Video
Before Issue Fix | After Issue Fix |
|----------|----------|
|<video width="40" height="60" alt="Before Fix"
src="https://github.com/user-attachments/assets/0acc28a6-a526-4799-8de7-99c4b0dbf4fe">|<video
width="50" height="40" alt="After Fix"
src="https://github.com/user-attachments/assets/61100874-a442-4a50-96ee-0539a2544ac3">|
…dices with grouped items (#34240)

> [!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 CollectionView's IsGrouped property is set to true, the values
of FirstVisibleItemIndex, CenterItemIndex, and LastVisibleItemIndex in
the ItemsViewScrolledEventArgs passed to the Scrolled event handler are
incorrect.

### Root Cause

- Visible items were sorted only by Row, which produced incorrect
ordering when items from multiple sections were visible simultaneously.

### Description of Change

**iOS (ItemsViewDelegator.cs and ItemsViewDelegator2.cs)**

- Changed the sort from .OrderBy(x => x.Row) to .OrderBy(x =>
x.Section).ThenBy(x => x.Row) so that IndexPathsForVisibleItems is
ordered correctly across section boundaries. The fix is applied to both
the legacy handler (Items/) and the current handler (Items2/).

### Issues Fixed
Fixes #17664 


### Validated the behaviour in the following platforms

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

Android fix PR: #31437

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/3612815d-3a43-4dd5-8d2c-3832e3d4a077">
| <video
src="https://github.com/user-attachments/assets/f6cd63b8-1ed9-465a-99d9-11e38b004dac">
|
)

<!-- 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
Label.Clip did not clip the background on iOS and Windows when
`Background` was also set. The background rendered outside the clipping
geometry.

### Root Cause
When a Label has a non-null Background, LabelHandler.NeedsContainer
returns true, wrapping the label in a WrapperView.
 
**iOS**: MapBackground called handler.ToPlatform(), which returns the
WrapperView when a container is present. The background was applied to
the wrapper, but WrapperView.SetClip() only masks sublayers named
MauiBackgroundLayer — solid colors set via BackgroundColor are not
sublayers, so they were never masked.

### Description of Change

**iOS**: Changed MapBackground to use
handler.PlatformView?.UpdateBackground(label) (routes to MauiLabel)
instead of handler.ToPlatform() (routes to WrapperView). The WrapperView
clip then correctly clips the label and its background together.

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

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/415fa851-7a19-4874-8afb-f240d3962067"
>| <video
src="https://github.com/user-attachments/assets/59c24428-0631-43a9-9720-f22649a20f82">|
…ting 4+ images with CompressionQuality set (#34281)

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

### Issue Details
On iOS, when using MediaPicker.PickPhotosAsync() with CompressionQuality
enabled and SelectionLimit = 0 (unlimited), selecting several photos
returns an empty list instead of the selected photos.

### Root Cause
When compression is enabled, the original implementation eagerly loads
and processes all selected photos immediately after the picker is
dismissed by calling NSItemProvider.LoadDataRepresentationAsync()
sequentially in a tight loop.
When four or more items are processed in rapid succession, these data
loads fail or time out on iOS. As a result, the operation fails and
returns an empty list. This occurs because multiple instances cannot
reliably load data simultaneously or immediately after the picker view
controller is dismissed.
 
### Description of Change
The fix introduces a lazy compression approach using a new
PHPickerProcessedFileResult wrapper. Image processing is deferred until
the stream is actually opened, avoiding iOS resource constraints caused
by eager loading of multiple instances in quick succession.
The changes now aligns with MAUI Graphics limitations: image.SaveAsync
supports only JPEG and PNG output formats. Therefore, when a non-PNG
image is compressed, JPEG is the only valid output format.

### Issues Fixed
Fixes #33954

### Tested platforms

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

**Regarding the test case:** MediaPicker invokes the native iOS photo
picker, which is a system-level UI running outside the app process.
Because of this, it cannot be controlled or captured by Appium or other
automated test frameworks. Therefore, the test case is ignored.

**Key changes in `MediaPicker.ios.cs`:**
- Added `PHPickerProcessedFileResult` class (~67 lines) — wraps a
`FileResult` and defers all NSItemProvider I/O to stream-open time
- Modified `PickerResultsToMediaFiles()` — wraps results in
`PHPickerProcessedFileResult` instead of eagerly compressing

### Screenshots

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/18e6f361-0ba4-4176-9f25-5c0e07a32b3c">
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/435083d5-301b-4e8f-9daf-94b324f63356">)
|
> [!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 Detail
SearchBar.CancelButtonColor has no effect on iOS 26 (Liquid Glass
design). On iOS 18.x, the cancel button shows "Cancel" text and
CancelButtonColor is correctly applied via SetTitleColor. On iOS 26,
Apple redesigned the cancel button — it now shows an "xmark" icon (a
UIButton with accessibility label "Close") instead of text. All standard
color APIs (SetTitleColor, TintColor,
UIButtonConfiguration.BaseForegroundColor) are silently overridden by
UIButton's Liquid Glass compositor on every layout pass, so the X icon
always renders in the system default color regardless of
CancelButtonColor.

### Root Cause
UIButton on iOS 26 renders the X icon through its own Liquid Glass
compositor — a system-level final rendering pass that runs after all
UIKit APIs, CALayer, and CALayer.Filters. The compositor is scoped to
UIButton's own view subtree, meaning any color applied inside the button
(text color, tint, image, configuration, sublayer) is overridden before
it reaches the screen.

### Description of Change
On iOS 26, UIButton renders the X icon through the Liquid Glass
compositor, which runs after all UIKit APIs and overrides any color set
on the button or its subviews. To work around this, instead of coloring
the button itself, the fix renders a colored "xmark" icon image using
UIGraphicsImageRenderer with CGBlendMode.SourceIn (baking the color into
the pixels so UIKit cannot override it) and places it in a separate
UIImageView next to the cancel button in the view hierarchy — completely
outside UIButton's rendering scope. The overlay is positioned to sit
exactly on top of the X icon and has UserInteractionEnabled = false so
taps still reach the real cancel button underneath.
The cancel button lookup uses FindDescendantView<UIButton> with a
predicate btn.FindParent(v => v is UITextField) == null to ensure only
the cancel button is matched, excluding the clear button inside the text
field. The overlay is deferred via DispatchAsync so the cancel button
frame is valid after layout, and a WeakReference<UISearchBar> is used to
avoid retain cycles and always look up the current cancel button
instance across theme transitions.

### Issues Fixed
Fixes #33964

**Regarding the test case:** The [AppTheme feature
matrix](https://github.com/dotnet/maui/tree/main/src/Controls/tests/TestCases.HostApp/FeatureMatrix/AppTheme)
already covers the SearchBar cancel button color in both light and dark
themes through LightTheme_SearchBar_VerifyVisualState and
DarkTheme_SearchBar_VerifyVisualState. Therefore, no additional tests
are added.

### Files Changed

- `src/Core/src/Platform/iOS/SearchBarExtensions.cs` — iOS 26 overlay
fix

### Key Technical Details
- `CGBlendMode.SourceIn` recolors only the xmark pixels while preserving
the icon shape and transparency
- `UIImageRenderingMode.AlwaysOriginal` prevents UIKit from re-tinting
the baked image after placement
- `UserInteractionEnabled = false` on the overlay ensures taps fall
through to the real cancel button
- `CancelButtonColorOverlayTag = 0x53424343` (encodes "SBCC") identifies
the overlay for cleanup on color change or cancel button removal
- `WeakReference<UISearchBar>` avoids retain cycles; the cancel button
itself is looked up fresh on each dispatch since iOS 26 may recreate it
during theme transitions
- This change only applies to `OperatingSystem.IsIOSVersionAtLeast(26)`
— pre-iOS 26 behavior is unchanged

### Screenshots

Light Theme:
| Before Issue Fix | After Issue Fix |
|----------|----------|
|<img width="762" height="1682" alt="Image"
src="https://github.com/user-attachments/assets/24e30082-096a-4fc3-b75d-51ca8994e8f5"
/>|<img width="762" height="1682" alt="Image"
src="https://github.com/user-attachments/assets/66c83175-a4a8-40d1-9a9f-6bddb21857e2"
/>|

Dark Theme:
| Before Issue Fix | After Issue Fix |
|----------|----------|
|<img width="762" height="1682" alt="Image"
src="https://github.com/user-attachments/assets/1aeb1bac-9c51-4df0-8afe-d189f7fec46c"
/>|<img width="762" height="1682" alt="Image"
src="https://github.com/user-attachments/assets/584b1cd2-ab53-4631-bb1b-626554000591"
/>|
)

This pull request adds a new Shell feature matrix to the test cases host
app, providing a dedicated UI for testing and exploring Shell navigation
features in .NET MAUI. The main changes introduce new pages for the
Shell feature matrix, including a main page and a comprehensive options
page to test navigation events and stack manipulation.

**Shell Feature Matrix Integration**

* Added a new `ShellFeaturePage` to the feature matrix in
`CorePageView.cs`, making Shell navigation features accessible from the
gallery of test pages.
* Implemented `ShellFeaturePage.xaml` and its code-behind, providing a
main entry point for Shell navigation testing, including a button to
launch the navigation control page.
[[1]](diffhunk://#diff-429088ce96d697ab4ebcb64f4f34eab95990318df0e699a206770e487cc5f99cR1-R17)
[[2]](diffhunk://#diff-d9fe6832827db8c2b917b1667eb42de532a901608d7f118f002848d9a7fc5018R1-R25)

**Shell Navigation Options UI**

* Added `ShellNavigationOptionsPage.xaml`, a comprehensive UI for
testing Shell navigation options, including navigation events, stack
inspection, and tab navigation methods. This page uses data binding to
display current navigation state and exposes buttons for navigation
stack manipulation.

**New Issue Identified**

-  #34318

**Existing Issue Identified**

- [On Windows TextOverride and IconOverride is not
working](#1625)

https://github.com/user-attachments/assets/9ab48004-334a-45d9-95db-aaf42de2b083

---------
Co-authored-by: Jakub Florkowski <kubaflo123@gmail.com>
# Conflicts:
#	.github/scripts/Review-PR.ps1
#	eng/pipelines/ci-copilot.yml
…n called before the view is mounted (#34331)

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

### Root Cause:

The issue occurs because CollectionView (Items2 /
CollectionViewHandler2) depends on the native UIKit layout pass to
compute its content size. When Measure() is called before the view is
mounted, the native collection view has not performed layout yet, so
ContentSize remains {0,0}. MAUI then falls back to
base.GetDesiredSize(), which returns the full constraint height,
producing an incorrect measured value.

### Fix Description:

The fix involves performing a temporary in-place layout pass during
pre-mount measurement. If Window == null, the CollectionView frame is
set directly to the given constraints (clamping ∞ to 10000 to match
UIKit’s UILayoutFittingExpandedSize). Then SetNeedsLayout() and
LayoutIfNeeded() are called so UIKit computes the real content size. The
original frame is always restored in a finally block. No AddSubview,
RemoveFromSuperview, or ReloadData() is used. This allows Measure() to
return the correct height even before the control is mounted.
 
**Reason for Mac behavior:**
 
On macOS via MacCatalyst, UISheetPresentationController always presents
sheets as full-height modal panels. Custom detents (custom heights) are
ignored by the platform.

### Issues Fixed
Fixes #32983

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

### Output Screenshot
Before Issue Fix | After Issue Fix |
|----------|----------|
|<video width="100" height="100" alt="Before Fix"
src="https://github.com/user-attachments/assets/8f31b5fe-6482-490c-b6f4-c77376257042">|<video
width="100" height="100" alt="After Fix"
src="https://github.com/user-attachments/assets/d0b2e698-8843-4d9b-a773-0bd3db427b7c">|
…t tab becomes invisible (#34372)

<!-- 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
Setting IsVisible = false on the first tab's page in a Shell with 7 tabs
causes the bottom tab bar to display incorrect tabs on Android and
breaks sub-page navigation on iOS.

- On Android, the tab bar is not rebuilt — Tab1 remains visible and Tab5
ends up highlighted at the wrong index (Tab4 appears selected instead of
Tab5).
- On iOS, navigating to a sub-page from Tab5 after Tab1 is hidden pushes
onto MoreNavigationController instead of the tab's own navigation stack,
causing the page to not display.
- Both bugs are triggered by _tab1Page.IsVisible = false followed by
Shell.Current.GoToAsync("///Tab5").

### Root Cause
**Android**: SetupMenu() has an early return if (DisplayedPage is null).
When Tab1 becomes invisible, Shell transitions CurrentItem to a
lazy-loaded tab (ContentTemplate), making DisplayedPage transiently
null. SetupMenu() returns early, leaving BottomNavigationView stale with
Tab1 still in the menu. When GoToAsync("///Tab5") fires,
GetItems().IndexOf(Tab5) returns 3 (Tab1 excluded), but menu.GetItem(3)
points to Tab4 in the stale menu — wrong tab is highlighted.

**iOS**: After Tab1 is removed, IsInMoreTab is never recalculated. Tab5
was at index 4 (IsInMoreTab = true) before removal; after it shifts to
index 3 (a direct tab), its renderer still holds IsInMoreTab = true,
causing GoToAsync("Page51") to be routed through
MoreNavigationController where it fails to display.

### Description of Change
**Android**: Changed SetupMenu() guard from if (DisplayedPage is null) →
if (DisplayedPage is null && !_menuSetup). Allows rebuild during tab
transitions when menu was already initialized, first-time setup guard
unchanged.

**iOS**: Added UpdateIsInMoreTabForRenderers() after tab removal in
OnShellItemsChanged. Recalculates IsInMoreTab for all remaining view
controllers based on their new position relative to the 5-tab limit.

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

### Output  ScreenShot

Android

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/6ec28df8-47f2-490b-981b-170fc4d7dea9"
>| <video
src="https://github.com/user-attachments/assets/91f2faf3-6153-4951-975c-e25c19fa4ef3">|

iOS

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/2b632528-082e-4eb1-8d3a-09871c78c903"
>| <video
src="https://github.com/user-attachments/assets/8122082c-80a1-4408-a51e-0069244f0b69">|
…erView item holders (#34452)

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

### Root Cause:

The issue occurs because of RecyclerView reusing stale ViewHolders from
its shared recycled-view pool when CollectionView.EmptyView is swapped
on Android. When EmptyView or EmptyViewTemplate is updated,
EmptyViewAdapter._emptyItemViewType changes. However, the RecyclerView
recycled-view pool may still contain ViewHolders created for previous
item view types. As a result, RecyclerView can reuse one of these stale
holders at the empty position, causing a previously filtered data item
view to be rendered instead of the intended EmptyView.

### Fix Description:

The fix involves clearing the RecyclerView recycled-view pool during the
EmptyView update path. Specifically, GetRecycledViewPool().Clear() is
added in MauiRecyclerView.UpdateEmptyView() and executed only when the
currently attached adapter is _emptyViewAdapter (GetAdapter() ==
_emptyViewAdapter). This ensures that any stale ViewHolders are removed
before _emptyViewAdapter.NotifyDataSetChanged() refreshes the view,
preventing RecyclerView from reusing incorrect holders while keeping the
existing adapter behavior unchanged.

### Issues Fixed
Fixes #34122

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

**Note:** 

### Output Screenshot
Before Issue Fix | After Issue Fix |
|----------|----------|
|<video width="100" height="100" alt="Before Fix"
src="https://github.com/user-attachments/assets/f0dda99c-9eff-4078-8b87-72822fa52e13">|<video
width="100" height="100" alt="After Fix"
src="https://github.com/user-attachments/assets/ac702989-048c-440d-9f3c-a767b0f6eb4f">|

---------

Co-authored-by: Shane Neuville <5375137+PureWeen@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <kubaflo123@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sing scroll/rendering issues (#27093)

### Description of Change

Vertical padding set on the recyclerView affected the rendering process.
It is much more efficient to fully rely on ItemDecoration to manage
spacing between items.

### Issues Fixed

Fixes #24511
Fixes #8422
Fixes #18367
Fixes #17127
Fixes #30979
Fixes #31966

|Before|After|
|--|--|
<video
src="https://github.com/user-attachments/assets/e19124a4-c0ba-4796-9906-f6179fa77ba1"
width="300px"/>|<video
src="https://github.com/user-attachments/assets/f60fee7b-41dc-4b08-a7a0-a464c1a897dc"
width="300px"/>|
<video
src="https://github.com/user-attachments/assets/3827b6fc-bed2-4a80-8422-2ea7602e9970"
width="300px"/>|<video
src="https://github.com/user-attachments/assets/55daaee6-f198-40d9-b20a-fbb185001954"
width="300px"/>|

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ews when SearchBoxVisibility changes at runtime (#33774)

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

When `SearchBoxVisibility` is `Collapsible`,
`ShellToolbarTracker.UpdateToolbarItems` adds a placeholder menu item
(id `_placeholderMenuItemId`) to the toolbar menu and sets the
`_searchView.View` as that item's action view. When transitioning to
`Expanded`, the old code only checked whether `_searchView.View.Parent
!= _platformToolbar` and added the view directly to the toolbar — but
never removed the placeholder menu item from the menu. As a result, both
the menu item (showing the collapsible search icon) and the
directly-added expanded search view were displayed simultaneously.

The reverse transition (Expanded → Collapsible) did not have this
problem because the Collapsible path always calls
`menu.RemoveItem(_placeholderMenuItemId)` before re-adding it fresh.

### Description of Change

In `ShellToolbarTracker.cs`, the `Expanded` branch of
`UpdateToolbarItems` now explicitly removes the placeholder menu item
from the toolbar menu before adding `_searchView.View` directly to
`_platformToolbar`:

```csharp
else if (SearchHandler.SearchBoxVisibility == SearchBoxVisibility.Expanded)
{
    // Remove the placeholder menu item, if it exists, added for collapsible mode.
    if (menu.FindItem(_placeholderMenuItemId) is not null)
    {
        menu.RemoveItem(_placeholderMenuItemId);
    }

    if (_searchView.View.Parent != _platformToolbar)
    {
        _platformToolbar.AddView(_searchView.View);
    }
}
```

Several null-check expressions were also modernized from `!= null` / `==
null` to the C# `is not null` / `is null` pattern as part of the same
edit.

### Files Changed

- **`ShellToolbarTracker.cs`** — Core fix: remove placeholder menu item
in the Expanded branch; style cleanup (null-checks, brace style)
- **`TestCases.HostApp/Issues/Issue33772.cs`** — New test page: Shell
with buttons to toggle `SearchBoxVisibility` between Collapsible and
Expanded
- **`TestCases.Shared.Tests/Tests/Issues/Issue33772.cs`** — Two ordered
UI tests validating the transition in both directions via screenshot
- **Snapshot PNGs** — Baseline screenshots for Android, iOS, and Windows

### Issues Fixed

Fixes #33772

### Platforms Tested

- [x] Android
- [x] iOS
- [ ] Mac
- [ ] Windows
</details>


### Screenshot
| Before Fix | After Fix |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/716652d6-7f39-4c64-8fa9-262dd8cb2908">
| <video
src="https://github.com/user-attachments/assets/403990ac-d6fd-4b8c-8114-ff1cdf955df3">
|
…et to null (#31340)

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

- The BackgroundColor and Background of a ContentView are not properly
cleared when set to null on Android and iOS platforms.

### Root Cause

- The existing platform-specific logic on both Android and iOS only
handled background clearing for specific view types, such as
LayoutViewGroup or LayoutView. ContentView was not included in these
type checks. As a result, if a ContentView previously had a background
applied—such as a color or gradient—and was later set to null, the
background remained visible. This occurred because the rendering logic
did not execute the background-clearing code for ContentView, leading to
incorrect visual behavior.

### Description of Change

- Updated UpdateBackground extension methods on Android and iOS to
ensure that setting the background or background color to null correctly
clears the background for both LayoutView and ContentView types.


### Issues Fixed
Fixes #18933 

### Validated the behaviour in the following platforms

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

### Output
| Platform | Before | After |
|----------|----------|----------|
| Android | <video
src="https://github.com/user-attachments/assets/5d3ac9aa-3dbe-4841-9847-6b7a1484e141">
| <video
src="https://github.com/user-attachments/assets/5ccb6afb-8d3e-420b-8255-e0325fe6e6ad">
|
| iOS | <video
src="https://github.com/user-attachments/assets/9d7659f5-3409-4677-862e-fb0ee1853128">
| <video
src="https://github.com/user-attachments/assets/8851de12-bdc5-4633-aaec-9bf2be940450">
|
… between flyout items (#29883)

### Root Cause:
- On Android, the BottomNavigationView initially has a ColorDrawable
with a white background, which is the default color during its creation.
- Later, the BottomNavigationView background is changed to a
ColorChangeRevealDrawable with an animation, transitioning to the color
specified by IShellAppearanceElement.EffectiveTabBarBackgroundColor.
- Since the previous background color (white) differs from the current
color (black), the animation displays a transition from white to black
when switching pages.
### Description of Change:
- To resolve this issue, the
IShellAppearanceElement.EffectiveTabBarBackgroundColor is applied to the
background of the BottomNavigationView immediately after its creation.
- This ensures that no animation is triggered later, as the previous
background color (black) and the current color (black) remain the same.
 
**Tested the behaviour in the following platforms.**
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Reference
N/A
 
### Issues Fixed
Fixes #16522
 
### Screenshots
 
| Before | After |
|--------|-------|
| <img
src="https://github.com/user-attachments/assets/3e14b05f-70dd-4a17-bd85-01bf53f37095"
width="300" height="600"> | <img
src="https://github.com/user-attachments/assets/5320a886-ba23-4142-b4fb-6d00a53f3323"
width="300" height="600"> |
…th nullable types (#33429)

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

Fixes #33420

This PR fixes a that occurs when using with nullable types during Shell
navigation.

## Root Cause

In `ShellContent.ApplyQueryAttributes`, the code used
`Convert.ChangeType(value, prop.PropertyType)` which fails when the
property type is nullable (e.g., `long?`, `int?`) because
`Convert.ChangeType` does not handle `Nullable<T>` types directly.

When a user navigates with a nullable parameter like:
```csharp
Dictionary<string, object> param = new() {
    { nameof(DetailsPage.ID), (long?)1 }
};
await Shell.Current.GoToAsync(nameof(DetailsPage), param);
```

And the destination page has:
```csharp
[QueryProperty(nameof(ID), nameof(ID))]
public partial class DetailsPage : ContentPage
{
    public long? ID { get; set; }
}
```

The app would crash with `InvalidCastException`.

## Solution

Use `Nullable.GetUnderlyingType()` to extract the underlying type before
conversion:

1. Check if the property type is nullable using
`Nullable.GetUnderlyingType()`
2. If nullable, extract the underlying type (e.g., `long` from `long?`)
3. Convert the value to the underlying type
4. Assign (automatic wrapping in nullable occurs)
5. Handle null values explicitly

## Changes

**Fix:**
- `src/Controls/src/Core/Shell/ShellContent.cs` - Added nullable type
handling in `ApplyQueryAttributes`

**Tests:**
- Added UI test `Issue33420` that reproduces the issue and verifies the
fix
- Test navigates with a nullable `long?` parameter and verifies
navigation succeeds

## Testing

✅ Tests fail without the fix (reproduces the crash)
✅ Tests pass with the fix (navigation works)
✅ Verified on iOS simulator

## Platforms Affected

All platforms (iOS, Android, Windows, MacCatalyst) - Shell navigation
code is shared.

---------
…d HeightRequest Values (#27449)

### Root Cause 

When the height or width is infinity, the size is measured using the
platform-specific SizeToFit method. However, SizeToFit directly returns
the calculated size to the SearchBar without ensuring that explicit
values are applied. Since the base measurement only ensures explicitly
set values, the SearchBar results do not properly account for the
intended dimensions.

### Description of Change

Enhanced the SearchBar's dimension handling by validating explicit size
requests, ensuring that defined width and height constraints are
correctly applied and preserved.

**Tested the behaviour in the following platforms**

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

### Issues Fixed

Fixes #27427 

### Output

MAC

|Before|After|
|--|--|
|<img
src="https://github.com/user-attachments/assets/e2a874d8-a3d9-4b5a-ac38-f660fc834479">|
<img src
="https://github.com/user-attachments/assets/9d72e84f-79bc-49ba-9153-15150be43db5">|

iOS

|Before|After|
|--|--|
|<img
src="https://github.com/user-attachments/assets/e59022fe-4bb1-4af1-aa64-3b2ad1faaf9f">|
<img src
="https://github.com/user-attachments/assets/ac060565-d279-42cd-8f37-c66b9bdadf16">|
<!-- 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

Corrects label padding handling in RTL mode by using SetPaddingRelative
on Android and flipping left/right insets on iOS. Adds test cases and UI
tests to verify correct padding mirroring for labels in RTL layouts.


### 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 #32316

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

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Shalini-Ashokan and others added 11 commits March 24, 2026 10:45
…e rows (#34492)

<!-- 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
When the same swipe actions are shared across multiple rows, swiping a
second row while the first is still open causes an Android crash.

### Root Cause
Each swipe action reuses a cached Android button view. When shared, the
same button is already attached to the first row's view tree. Android
does not allow adding an already-parented view to another parent.

### Description of Change
When a shared swipe action's Android button is already attached to
another row, the handler is disconnected to force creation of a new
button. The new button is then safely added to the current row without
conflict.
 
Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #19331  

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/31ebd578-ce07-4d41-b067-c35a3a4a4d49"
>| <video
src="https://github.com/user-attachments/assets/382b3359-d318-43ef-bdab-590013e50165">|
### Description of Change

When publishing a MAUI Blazor Hybrid app as a single-file executable
(`PublishSingleFile=true`), static web assets including scoped CSS
(*.styles.css) were not being included in the single-file bundle. At
runtime, the `EmbeddedFileProvider` looks for these assets in the
extraction directory
(`%LOCALAPPDATA%\Temp\.net\<AppName>\<hash>\wwwroot\`), but they were
never extracted because they weren't bundled.

Root Cause: The Static Web Assets SDK was designed for ASP.NET Core web
servers where static assets should be excluded from single-file bundles
(to be served by static file middleware). This is the opposite of what
MAUI Blazor Hybrid needs - assets must be included in the bundle for the
embedded file provider to work.

The Fix: Added a new MSBuild target
`_IncludeComputedStaticWebAssetsInSingleFileBundle` that runs after
`_ComputeFilesToBundle` and adds
`@(_PublishStaticWebAssetsPreserveNewest)` items with
`SourceType=Computed` to `@(_FilesToBundle)`. This ensures computed
assets (like scoped CSS bundles) are bundled and extracted at runtime.

### Discussion of decisions made:

- `@(_PublishStaticWebAssetsPreserveNewest)` was chosen because it
preserves all static web asset metadata including SourceType
- We filter for `SourceType=Computed` to only include generated assets
(like scoped CSS bundles) that didn't flow through the normal
`@(ResolvedFileToPublish)` path. User-placed files in wwwroot
`(SourceType=Discovered)` are already included via the normal publish
flow.
- We must add to `@(_FilesToBundle)` directly, not
`@(ResolvedFileToPublish)`, because `_ComputeFilesToBundle` has already
run by the time our target executes
- The timing (`AfterTargets="_ComputeFilesToBundle" +
BeforeTargets="PrepareForBundle"`) ensures items are added before
`PrepareForBundle` copies them to `@(FilesToBundle`)

### Issues Fixed

Fixes ##33587

### Testing

I tested it by changing the corresponding `.targets` file in my nuget
cache and run the reproduction on the repo provided with the issue. By
checking the runtime location I confirmed that styles are present when
the fix is applied.
…sts (#34613)

This PR removes the duplicate test that was added while rebasing PR
#33632 to address the build error in
the in-flight/current branch.

### Test Case:

- VerifyFlowDirectionRTLAndKeepScrollOffsetWithGroupedList
<!-- 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 the Windows platform, setting the CharacterSpacing property on a
DatePicker control has no visible effect.

### Description of Change

<!-- Enter description of the fix in this section -->
Applied the CharacterSpacing value to the native TextBlock in the
Windows handler to ensure the DatePicker displays character spacing
correctly

### 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 #30066 

<!--
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> <img
src="https://github.com/user-attachments/assets/ba5c196b-301e-4d8b-b579-c32a5dd7174e"
width="600" height="300"> | **Windows**<br> <img
src="https://github.com/user-attachments/assets/47f7ce0c-754a-4040-b522-5d0b9244d648"
width="600" height="300"> |
…33959)

<!-- 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
When resizing the window smaller on Windows, images in a CarouselView
shift downward.

**Regressed PR:** [PR-26865](#26865)

### Root Cause
PR #26865 changed InvalidateItemSize() to call
ListViewBase.InvalidateMeasure() instead of calling InvalidateMeasure()
on each individual ItemContentControl. This fixed a layout cycle
exception (issue #26822) but prevented items from properly updating
their layout when dimensions changed, causing the image shift.

### Description of Change
Modified InvalidateItemSize() to update item dimensions immediately,
then defer the individual item invalidation using
DispatcherQueue.TryEnqueue(). This queues the invalidation to run after
the current layout pass completes, avoiding the layout cycle exception
while ensuring items properly remeasure with their new dimensions.

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

**Reference:**

[Handlers/ListView/Windows/ListViewRenderer.cs#L656](https://github.com/dotnet/maui/blob/main/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/ListViewRenderer.cs#L656)

[Handlers/RefreshView/RefreshViewHandler.Windows.cs#L152](https://github.com/dotnet/maui/blob/main/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Windows.cs#L152)

[Handlers/HybridWebView/HybridWebViewHandler.Windows.cs#L39](https://github.com/dotnet/maui/blob/main/src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Windows.cs#L39)

### Issues Fixed

Fixes #32017

### Screenshots

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/8e8ea4d9-d21d-481d-a2d2-8fcdaed59608">
| <video width="300" height="600"
src="https://github.com/user-attachments/assets/3f94efa3-726a-4289-b6e4-782a59382314">)
|
### Issue Details:
NullReferenceException is thrown when rendering image paint in Mac and
iOS platforms.

### Root Cause:
"The _fillImage is set to null after the canvas is restored, but the
DrawImageCallback is called after restoring the canvas. As a result, a
NRE (Null Reference Exception) is thrown.

### Description of Change:
Introduced a new variable to store the _fillImage value and added a null
check before calling the ToPlatformImage(). The image is drawn inversely
so removed the transformation logic.

Reference:

https://github.com/dotnet/maui/blob/17a8b5a23aabbc10d01b5477cc1220c3135ecd46/src/Graphics/src/Graphics/Platforms/MaciOS/PlatformCanvas.cs#L740-L742

Validated the behaviour in the following platforms

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


### Issues Fixed

Fixes #19642

### Output

| Before | After |
| ------ | ----- |
|<img width="668" alt="image"
src="https://github.com/user-attachments/assets/6ca40fbf-074e-44bb-b2b5-4caae49bd7d3"
/>| <img width="382" alt="image"
src="https://github.com/user-attachments/assets/e98aadbb-746a-42e9-953a-37aa20cba398"
/>|

---------
…oogle Map (#33855)

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

Issue 1: When clearing the MapElements.Clear(); on the button click. The
polygon were not cleared from visual.
Issue 2: The polygons were not updated in the visual when set the alpha
property to 0 for the existing polygon on the button click.
        
### Root Cause:

When Add / Clear the MapElements, it calls the MapElements method and
executed ClearMapElements() followed immediately by AddMapElements().
The Google Maps Android SDK batches internal rendering updates, so the
Remove() calls were queued but not visually processed before new
elements were added. Additionally, the original "clear all and re-add"
pattern caused duplicate elements when the mapper was called multiple
times rapidly.

### Description of Change:

Two changes were made to MapHandler.Android.cs:

Wrapped operations in Post() - Schedules the sync operation to run on
the UI thread in the next message loop iteration, giving the Google Maps
SDK time to process pending visual updates. The post is only used for
runtime changes and on initial loading the mapHandler.Map is null, so
avoided post for intial loading.
 
Replaced clear-and-add with SyncMapElements() - A smarter sync approach
that:
- Builds a HashSet of new element IDs from the incoming collection. 
- Only removes native elements whose IDs are no longer in the new
collection.
- Builds a HashSet of remaining existing element IDs
- Only adds elements that don't already exist on the map
- Sets lists to null when they become empty (for memory cleanup)

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

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

### Reference:


https://github.com/xamarin/Xamarin.Forms/blob/2f8f4864a4d289dc89a6228e2ca9d6a49993e365/Xamarin.Forms.Maps.Android/MapRenderer.cs#L564

### Issues Fixed:

Fixes  #33635   

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/3394db3d-5d4f-4d03-b2c0-297f695738a2"
Width="300" Height="600"> | <Video
src="https://github.com/user-attachments/assets/7821fd65-bf4a-4d2a-b098-22176701680e"
Width="300" Height="600"> |

---------
…ing Wifi (turning it on or off) (#29606)

### Issue Details:

The Connectivity.ConnectivityChanged event is not triggered for iOS
platform when toggling wifi (turning it on or off)
        
### Root Cause:

When toggling Wifi (turning it on or off). The native iOS triggers
OnChange() method, Inside this method, a delay of 100 milliseconds was
used to allow the system time to update the network state before
checking connectivity. The OnChange() method when compare the current
NetworkAccess with the previous NetworkAccess value after the 100 milli
seond delay the current NetworkAccess value is not updated and still it
remains previous value. So, here the 100 milli seconds delay is not
enough to settle the internal network state transition.

### Description of Change:

To address this, the delay was increased from 100 milliseconds to 400
milliseconds. This adjustment was tested on the iOS simulator and
provides sufficient time for the system's network state to fully
stabilize. As a result, the NetworkAccess value is updated correctly,
and the ConnectivityChanged event is triggered reliably.

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

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

### Reference:

N/A


### Issues Fixed:

Fixes #28961 

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/4223a4bc-3d42-47b4-b710-4ec45cf50869">
| <Video
src="https://github.com/user-attachments/assets/456bbe55-f9f8-411f-9322-394df5ae6a7f">
|
…ar when IsReadOnly is true (#29592)

<!-- 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, the property was not properly initialized with the correct
default value. Additionally, during initial loading, the property was
updated before the control was fully loaded, so the value was not
applied correctly.
 
- On Android, we missed disabling the clear button when IsReadOnly is
set to true. As a result, users were still able to clear the text even
though IsReadOnly was enabled.

### Description of Change

- On Windows, I updated the default value of the property and modified
the logic to update the property only if the control is fully loaded.
Since the value is also updated after loading, it will now be applied
correctly.
 
- On Android, I disabled the clear button when IsReadOnly is true. This
resolves the issue by preventing the text from being cleared when the
control is read-only

### Issues Fixed

Fixes #29547

### Tested the behaviour in the following platforms

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

### Screenshot

| Before Fix | After Fix |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/7db777e4-2961-4457-8da8-eac77ef6d636">
| <video
src="https://github.com/user-attachments/assets/112e1cca-d7b7-4022-b08d-e49ecd921f04">
|
| <video
src="https://github.com/user-attachments/assets/44944325-df70-460d-a5b6-28a104f679f6">
| <video
src="https://github.com/user-attachments/assets/6105bd07-50cf-4c49-bc28-a3eeae557404">
|

---------
…perty is changed to false (#27331)

### Issue Details

NullReference exception is thrown when disabling IsGrouped at runtime.

### Root Cause

The value passed as the itemsource when creating a groupItemsList is not
IEnumerable. This causes the value to be set as null.

### Description of Change

Ensured the value is of type IEnumerable and pass it to Create method of
TemplatedItemSourceFactory to avoid null reference exceptions.

Validated the behaviour in the following platforms

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

### Issues Fixed

Fixes #17864
Fixes #28824

### Output

| Before | After |
| ------ | ----- |
|<video
src="https://github.com/user-attachments/assets/a651b7ce-a1e7-4603-95bc-9638fc3cf7c7">|<video
src="https://github.com/user-attachments/assets/3729a956-d37e-4fc2-aaa2-ec4c43493054">|

---------
This PR addresses the build failures in the inflight/current branch by:
- Removing one UITestCategory from
ShouldAppearFlyoutIconAndContentPageTitle test; previously, two
UITestCategories were added.
- Added the GetDisplayDensity, GetAndroidDisplayDensity, and
GetIOSDisplayDensity methods again, which were removed in this PR:
#28474

### Test Case:
- ShouldAppearFlyoutIconAndContentPageTitle
- Issue28986_SafeAreaBorderOrientation
Copilot AI review requested due to automatic review settings March 24, 2026 15:50
@github-actions
Copy link
Contributor

github-actions bot commented Mar 24, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34617

Or

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR appears to be an “inflight” collection of fixes/regressions across Controls, XAML parsing/source-gen, Shell navigation/appearance, item handlers (Android/iOS/Windows), Maps, and BlazorWebView packaging/platform attributes, plus associated unit/device tests.

Changes:

  • Tighten/adjust runtime behaviors (e.g., StaticResource exceptions, Shell navigation/query behavior, swipe/pan gesture handling, various handler/layout edge cases).
  • Add/extend tests (Core unit tests + device tests) to cover multiple regressions (Maps, SwipeView, Shell, FlexLayout, etc.).
  • Update platform-specific implementations (Android/iOS/Windows) for visuals, selection/click listeners, measurement invalidation, and platform quirks; plus BlazorWebView single-file bundling + SupportedOSPlatform metadata.

Reviewed changes

Copilot reviewed 124 out of 1440 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/Controls/tests/DeviceTests/Xaml/StaticResourceTests.cs Adds device test asserting missing StaticResource throws even with handler present.
src/Controls/tests/DeviceTests/TestCategory.cs Adds Map test category constant.
src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.cs Adds iOS/MacCatalyst rendering tests for SearchBar Width/HeightRequest.
src/Controls/tests/DeviceTests/Elements/Map/MapTests.cs Adds iOS/MacCatalyst device tests for MapElementId reset behavior.
src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.Android.cs Uses platform helper for selection length + adds RTL selection length regression test.
src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.Android.cs Uses platform helper for selection length + adds RTL selection length regression test.
src/Controls/tests/DeviceTests/Elements/CollectionView/CollectionViewTests.Android.cs Adds tests asserting click listeners follow SelectionMode; adds layout helper.
src/Controls/tests/DeviceTests/ControlsDeviceTestExtensions.cs Registers Maps handlers for device tests (Android/iOS/MacCatalyst).
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj Adds Maps project references to device tests.
src/Controls/tests/Core.UnitTests/SwipeViewTests.cs Adds unit tests for SwipeView scroll parent discovery behavior.
src/Controls/tests/Core.UnitTests/ShellTests.cs Adds unit test for back navigation default animation behavior.
src/Controls/tests/Core.UnitTests/ShellElementCollectionTests.cs Adds regression tests for flyout observer notifications after dynamic item replacement.
src/Controls/tests/Core.UnitTests/Layouts/FlexLayoutTests.cs Adds multiple FlexLayout regression tests (arrange-only + flex-grow behavior).
src/Controls/tests/Core.UnitTests/Gestures/SwipeGestureRecognizerTests.cs Adds tests for swipe direction rotation transform + invalid rotations.
src/Controls/src/Xaml/XmlTypeXamlExtensions.cs Avoids static *Extension shadowing exact type resolution (#34021).
src/Controls/src/Xaml/MarkupExtensions/StaticResourceExtension.cs Always throws when static resource key missing (even with handler present).
src/Controls/src/Xaml/MarkupExtensions/BindingExtension.cs Avoids DataType assignment for non-relative explicit Source to prevent source-null-out.
src/Controls/src/Xaml/ApplyPropertiesVisitor.cs Ensures StaticResource exceptions are rethrown even when exception handler exists.
src/Controls/src/SourceGen/XmlTypeExtensions.cs Mirrors static *Extension shadowing guard in source-gen type resolution.
src/Controls/src/SourceGen/KnownMarkups.cs Fixes x:DataType resolution logic + reports a more specific diagnostic.
src/Controls/src/Core/Window/Window.cs Triggers SizeChanged when Width/Height bindable properties change (guarded by batch updates).
src/Controls/src/Core/VisualStateManager.cs Adds helper to detect Selected visual state.
src/Controls/src/Core/VisualElement/VisualElement.cs Preserves Selected state when computing visual state (vs forcing Normal/PointerOver).
src/Controls/src/Core/Toolbar/Toolbar.Android.cs Adjusts Android toolbar content insets when TitleView has margins/options set.
src/Controls/src/Core/SwipeView/SwipeView.cs Improves scroll parent discovery for templated scenarios; uses absolute deltas for close-on-scroll.
src/Controls/src/Core/Shell/ShellSection.cs Defaults back navigation animation to true when not specified.
src/Controls/src/Core/Shell/ShellNavigationManager.cs Adjusts query attribute application when popping and merged query is empty.
src/Controls/src/Core/Shell/ShellElementCollection.cs Tracks clear/add cycles to notify flyout observers when count reaches 2 after clear.
src/Controls/src/Core/Shell/ShellContent.cs Moves delayed query param propagation earlier; improves nullable conversion handling.
src/Controls/src/Core/Shell/Shell.cs Propagates NavBarIsVisible changes; adjusts navigating/navigated event timing and defers NavigatedTo until Loaded.
src/Controls/src/Core/Shell/SearchHandler.cs Avoids double query confirmation on WinUI when selecting item.
src/Controls/src/Core/Shell/BaseShellItem.cs Special-cases NavBarIsVisible propagation to read from Shell when appropriate.
src/Controls/src/Core/Shell/BackButtonBehavior.cs Prevents IsEnabledCore from re-enabling when IsEnabled is false.
src/Controls/src/Core/SearchBar/SearchBar.iOS.cs Adds mapping to update native UserInteractionEnabled based on IsEnabled/IsReadOnly/InputTransparent.
src/Controls/src/Core/SearchBar/SearchBar.Mapper.cs Refines SearchBar mapper behavior (iOS user interaction mapping; Android Material3 handler mapping selection).
src/Controls/src/Core/SearchBar/SearchBar.Android.cs Adds Material3 SearchBarHandler2 text mapping overload.
src/Controls/src/Core/RadioButton/RadioButton.Windows.cs Applies TextTransform to RadioButton content on Windows (Lowercase/Uppercase).
src/Controls/src/Core/RadioButton/RadioButton.Mapper.cs Maps TextTransform -> content update for Android/Windows.
src/Controls/src/Core/RadioButton/RadioButton.Android.cs Applies TextTransform to RadioButton text on Android (Lowercase/Uppercase).
src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt Tracks newly exposed iOS/MacCatalyst API surface changes.
src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt Tracks newly exposed iOS API surface changes.
src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt Tracks Android public API changes, incl. ShellRenderer color members update.
src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs Adds line break + character spacing propagation to spans; validates character spacing.
src/Controls/src/Core/Platform/Windows/Extensions/ToolbarExtensions.cs Disconnects TitleView handler before reusing in Windows toolbar TitleView updates.
src/Controls/src/Core/Platform/Windows/Extensions/FormattedStringExtensions.cs Adds character spacing inheritance/validation into formatted string spans on Windows.
src/Controls/src/Core/Platform/Windows/CollectionView/TemplatedItemSourceFactory.cs Returns empty items when itemsSource is null (Windows CollectionView).
src/Controls/src/Core/Platform/Windows/CollectionView/ObservableItemTemplateCollection.cs Skips group footer contexts when syncing underlying items source.
src/Controls/src/Core/Platform/Windows/CollectionView/ItemContentControl.cs Coalesces measure invalidations on item dimension changes via DispatcherQueue.
src/Controls/src/Core/Platform/Windows/CollectionView/GroupTemplateContext.cs Fixes footer insertion order/logic for group templates.
src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.iOS.cs Transforms swipe direction based on view rotation; changes simultaneous recognition against UIScrollView.
src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.Windows.cs Uses cumulative translation + marks manipulation events handled; avoids clearing pointer on active gestures.
src/Controls/src/Core/Platform/Android/TabbedPageManager.cs Prevents removing tabs on disappearing; adjusts bottom nav elevation w/ gradient background.
src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs Adjusts back button icon behavior and menu item title setting for tooltip color.
src/Controls/src/Core/Platform/Android/Extensions/FormattedStringExtensions.cs Adds character spacing inheritance/validation for Android formatted strings.
src/Controls/src/Core/Platform/Android/Extensions/EditTextExtensions.cs Replaces SetTextKeepState with Editable.Replace for safer programmatic updates + selection clamping.
src/Controls/src/Core/Platform/AlertManager/AlertManager.iOS.cs Avoids using a presented VC that is being dismissed when finding top VC.
src/Controls/src/Core/NavigationPage/NavigationPageToolbar.cs Keeps flyout hamburger accessible when back button is hidden.
src/Controls/src/Core/Layout/FlexLayout.cs Ensures arranged size respects updated Width/HeightRequest during arrange-only passes.
src/Controls/src/Core/Internals/SwipeGestureExtensions.cs Adds helpers to normalize rotation and transform swipe directions.
src/Controls/src/Core/IndicatorView/IndicatorStackLayout.cs Filters indicator items based on MaximumVisible.
src/Controls/src/Core/Hosting/AppHostBuilderExtensions.cs Expands handler registration set; includes Material3 alternatives when enabled.
src/Controls/src/Core/Handlers/Shell/ShellHandler.cs Adds FlyoutVerticalScrollMode mapping (Windows).
src/Controls/src/Core/Handlers/Shell/ShellHandler.Windows.cs Updates FlyoutVerticalScrollMode on loaded (Windows).
src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewDelegator2.cs Corrects visible item ordering for grouped sources and improves first visible index resolution.
src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs Forces compositional layout pre-mount to compute content size; fixes horizontal auto-height circular sizing.
src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.iOS.cs Fixes ItemsLayout property change subscription lifecycle + disconnect cleanup.
src/Controls/src/Core/Handlers/Items2/CarouselViewHandler2.iOS.cs Adds IsEnabled mapping to update CollectionView enabled state.
src/Controls/src/Core/Handlers/Items/iOS/ItemsViewDelegator.cs Same visible item ordering/first visible index update for legacy iOS handler path.
src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs Resets contentSize.Height for horizontal layouts when width is 0 to avoid circular sizing.
src/Controls/src/Core/Handlers/Items/StructuredItemsViewHandler.Windows.cs Sets ItemContainerStyle based on orientation for FormsListView.
src/Controls/src/Core/Handlers/Items/StructuredItemsViewHandler.Android.cs Updates adapter/scrolling mode/layout manager when ItemsLayout changes.
src/Controls/src/Core/Handlers/Items/SelectableItemsViewHandler.Android.cs Ensures adapter updates click listeners on selection mode changes.
src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Windows.cs Enqueues vector change handling; disconnects handlers during cleanup.
src/Controls/src/Core/Handlers/Items/CarouselViewHandler.iOS.cs Adds IsEnabled mapping for CarouselView iOS handler path.
src/Controls/src/Core/Handlers/Items/CarouselViewHandler.cs Maps IsEnabled for iOS/MacCatalyst; keeps ItemsLayout mapping for Tizen/Android.
src/Controls/src/Core/Handlers/Items/CarouselViewHandler.Windows.cs Removes explicit ListViewBase.InvalidateMeasure during item size invalidation.
src/Controls/src/Core/Handlers/Items/Android/TemplatedItemViewHolder.cs Recycles and clears disconnected view/template state to force handler recreation on rebind.
src/Controls/src/Core/Handlers/Items/Android/SpacingItemDecoration.cs Removes outer-edge spacing for grid/linear layouts based on span/orientation.
src/Controls/src/Core/Handlers/Items/Android/SelectableViewHolder.cs Adds ability to attach/detach click listeners dynamically based on selection mode.
src/Controls/src/Core/Handlers/Items/Android/RecyclerViewScrollListener.cs Defers RemainingItemsThresholdReached until RecyclerView is idle to avoid scroll-callback modification crash.
src/Controls/src/Core/Handlers/Items/Android/MauiRecyclerView.cs Guards invalid scroll positions; improves empty view recycling; updates spacing/padding behavior for grids.
src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs Fixes swipe disabled handling; scrolls to position after items source updates.
src/Controls/src/Core/Handlers/Items/Android/ItemsSources/ObservableGroupedSource.cs Adds bounds check for group index retrieval (returns null + debug log).
src/Controls/src/Core/Handlers/Items/Android/ItemContentView.cs Disconnects handlers during recycle before clearing content; cleans pixel size reset logic.
src/Controls/src/Core/Handlers/Items/Android/Adapters/StructuredItemsViewAdapter.cs Avoids MeasureFirstItem sizing logic on header/footer view types.
src/Controls/src/Core/Handlers/Items/Android/Adapters/SelectableItemsViewAdapter.cs Updates selection mode click listeners; disables selection/clickability for SelectionMode.None (accessibility).
src/Controls/src/Core/Handlers/Items/Android/Adapters/EmptyViewAdapter.cs Ensures template content has handler before measuring header/footer.
src/Controls/src/Core/Handlers/Items/Android/Adapters/CarouselViewAdapter.cs Disables selection on CarouselView adapter.
src/Controls/src/Core/Entry/Entry.Mapper.cs Adds Android Material3 EntryHandler2 mappings.
src/Controls/src/Core/Entry/Entry.Android.cs Adds EntryHandler2 mapping overloads for Material3 (ImeOptions/Text).
src/Controls/src/Core/Compatibility/Handlers/TabbedPage/iOS/TabbedRenderer.cs Updates flow direction handling and listens for FlowDirection changes.
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellSectionRootRenderer.cs Invalidates header layout on MacCatalyst when header frame changes.
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellSectionRenderer.cs Adds guards for iOS 26 pop dispatch; respects back button enabled; applies appearance to More controller; new override.
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs Adds keyboard hide observer to fix view mispositioning; adjusts hamburger behavior; disposes observer.
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellNavBarAppearanceTracker.cs Resets tint to default when user clears ForegroundColor.
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellItemRenderer.cs Applies disabled state for tabs; sets per-item disabled appearance; updates “More” tab membership after removals.
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/SearchHandlerAppearanceTracker.cs Fixes background reset/customization logic; removes forced cancel button behavior.
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/SafeShellTabBarAppearanceTracker.cs Uses foreground/disabled colors for tab appearance; sets disabled title attributes.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs Updates left button when FlyoutIcon/ForegroundColor changes; refines icon visibility cases; clears tint when none set.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarAppearanceTracker.cs Stops forcing tracker TintColor from shell foreground color.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellSectionRenderer.cs Stores shell toolbar instance; refreshes TitleView mapping when fragment becomes visible.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellRenderer.cs Updates default colors based on Material3 and adjusts theme detection.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellPageContainer.cs Uses Material3 surface color as background; refactors resource background selection.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs Updates bottom nav background color from appearance; avoids early return during menu setup.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFlyoutTemplatedContentRenderer.cs Renames inset listener to Shell-specific name and updates references.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellBottomNavViewAppearanceTracker.cs Tweaks default ColorStateList primary color for Material3.
src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs Adds iOS gesture delegate, flyout menu button updates, safety checks for rapid nav, iOS 26 disposal guard, tracker target changes.
src/Controls/src/Core/Button/Button.iOS.cs Preserves AlwaysTemplate rendering mode if explicitly set when resizing images.
src/Controls/src/Core/BindingExpressionHelper.cs Adjusts conversion logic around “0” and “-0” canonicalization for decimal types.
src/Controls/src/Core/BindingExpression.cs Skips type mismatch checks for explicit non-relative Source bindings.
src/Controls/src/Build.Tasks/XmlTypeExtensions.cs Mirrors static *Extension shadowing guard in build task type resolution.
src/Controls/samples/Controls.Sample/ViewModels/OthersViewModel.cs Removes legacy “Large Titles - iOS” entry from Others section.
src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSLargeTitlePage.xaml.cs Removes XAML code-behind for Large Title demo page.
src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSLargeTitlePage.xaml Removes XAML for Large Title demo page.
src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSLargeTitlePage.cs Reintroduces Large Title demo as pure C# UI + expanded scenarios.
src/Controls/samples/Controls.Sample/Pages/Others/LargeTitlesPageiOS.cs Removes older Large Titles demo page implementation.
src/Compatibility/Maps/src/iOS/MapRenderer.cs Tracks added MapElements to clear MapElementId on Reset/clear cycles.
src/Compatibility/Maps/src/Android/MapRenderer.cs Tracks added MapElements to clear MapElementId on Reset/clear cycles.
src/BlazorWebView/src/SharedSource/BlazorWebViewServiceCollectionExtensions.cs Uses BlazorWebView constants for SupportedOSPlatform attributes; adds MacCatalyst attribute.
src/BlazorWebView/src/Maui/build/Microsoft.AspNetCore.Components.WebView.Maui.targets Includes computed static web assets in single-file bundle.
src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj Sets SupportedOSPlatformVersion metadata (keep in sync with BlazorWebView constants).
src/BlazorWebView/src/Maui/BlazorWebViewHandler.cs Uses constants for platform support attributes across Android/iOS/MacCatalyst.
src/BlazorWebView/src/Maui/BlazorWebView.cs Adds platform support constants + applies them to attributes consistently.
eng/pipelines/common/ui-tests.yml Adds Essentials category to UI tests split categories list.

// even when an exception handler is present (for debug/hot reload scenarios).
// This prevents the app from crashing when relaunching.

Controls.Internals.ResourceLoader.ExceptionHandler2 = (ex) => { };
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

This test mutates a global static (ResourceLoader.ExceptionHandler2) but doesn’t restore the previous handler value. Please capture the original value before overwriting it and restore it in Dispose() (or via try/finally) to avoid cross-test coupling when other tests set the handler.

Copilot uses AI. Check for mistakes.
Comment on lines +46 to +49
public void Dispose()
{
Controls.Internals.ResourceLoader.ExceptionHandler2 = null;
}
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

This test mutates a global static (ResourceLoader.ExceptionHandler2) but doesn’t restore the previous handler value. Please capture the original value before overwriting it and restore it in Dispose() (or via try/finally) to avoid cross-test coupling when other tests set the handler.

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +43
bool exceptionThrown = false;
try
{
page.LoadFromXaml(xaml);
}
catch (Exception)
{
exceptionThrown = true;
}

Assert.True(exceptionThrown, "Expected an exception to be thrown for missing ControlTemplate");
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Prefer asserting exceptions directly (e.g., Assert.Throws<...>(() => ...)) instead of a boolean flag. This produces clearer failure output and avoids masking unintended exception types.

Suggested change
bool exceptionThrown = false;
try
{
page.LoadFromXaml(xaml);
}
catch (Exception)
{
exceptionThrown = true;
}
Assert.True(exceptionThrown, "Expected an exception to be thrown for missing ControlTemplate");
Assert.ThrowsAny<Exception>(() => page.LoadFromXaml(xaml));

Copilot uses AI. Check for mistakes.
Comment on lines +150 to +151
var handler = CreateHandler<SearchBarHandler>(searchBar);
var platformControl = GetPlatformControl(handler);
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

These iOS/MacCatalyst tests read UISearchBar.Frame immediately after handler creation without ensuring the control has been measured/arranged. Frame.Width/Height can legitimately be 0 (or differ due to layout rounding), making the test flaky. Consider placing the SearchBar into a parent, forcing a layout pass (measure/arrange + LayoutIfNeeded), and using a tolerance-based assertion.

Copilot uses AI. Check for mistakes.
Comment on lines +155 to +160
if (platformControl is UIKit.UISearchBar uiSearchBar)
{
actualWidth = uiSearchBar.Frame.Width;
}

Assert.Equal(requestedWidth, actualWidth);
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

These iOS/MacCatalyst tests read UISearchBar.Frame immediately after handler creation without ensuring the control has been measured/arranged. Frame.Width/Height can legitimately be 0 (or differ due to layout rounding), making the test flaky. Consider placing the SearchBar into a parent, forcing a layout pass (measure/arrange + LayoutIfNeeded), and using a tolerance-based assertion.

Copilot uses AI. Check for mistakes.

// do not canonicalize "-0"; user will likely enter a period after "-0"
if (stringValue == "-0" && DecimalTypes.Contains(convertTo))
if ((stringValue.StartsWith("0") || stringValue.StartsWith("-0")) && DecimalTypes.Contains(convertTo))
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

This broadens the previous special-case from exactly \"-0\" to any value starting with \"0\" (e.g., \"012\", \"0.5\", \"0\"). That can prevent conversion for valid numeric inputs with leading zeros and may regress numeric Entry typing behavior. Consider narrowing the condition to only the incremental-typing cases you want to preserve (e.g., \"-0\", \"0\", \"-0.\", \"0.\").

Copilot uses AI. Check for mistakes.
Comment on lines +168 to +170
// Get the filtered items source based on MaximumVisible
var itemsSource = GetFilteredItemsSource();
BindableLayout.SetItemsSource(this, itemsSource);
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Returning a snapshot List<object> as the BindableLayout ItemsSource breaks change notifications when the original ItemsSource is observable (e.g., ObservableCollection): subsequent adds/removes won’t update the indicators. If the intent is to cap visible items while preserving live updates, consider using a wrapper collection which implements INotifyCollectionChanged and stays in sync with the source, or keeping the original ItemsSource and handling MaximumVisible at the template/layout level.

Copilot uses AI. Check for mistakes.
Comment on lines +192 to +201
var filteredItems = new List<object>(_indicatorView.MaximumVisible);
foreach (var item in itemsSource)
{
if (filteredItems.Count >= _indicatorView.MaximumVisible)
{
break;
}

filteredItems.Add(item);
}
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Returning a snapshot List<object> as the BindableLayout ItemsSource breaks change notifications when the original ItemsSource is observable (e.g., ObservableCollection): subsequent adds/removes won’t update the indicators. If the intent is to cap visible items while preserving live updates, consider using a wrapper collection which implements INotifyCollectionChanged and stays in sync with the source, or keeping the original ItemsSource and handling MaximumVisible at the template/layout level.

Copilot uses AI. Check for mistakes.
Comment on lines +183 to +191
int totalCount = itemsSource is ICollection col
? col.Count
: itemsSource.Cast<object>().Count();

if (totalCount <= _indicatorView.MaximumVisible)
{
return itemsSource;
}

Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

For non-ICollection sources, Count() forces full enumeration, and the method then enumerates again to build the filtered list. This can be O(N) twice and can trigger side effects for streaming enumerables. Consider a single-pass approach which iterates until MaximumVisible + 1 (to detect overflow) without calling Count().

Suggested change
int totalCount = itemsSource is ICollection col
? col.Count
: itemsSource.Cast<object>().Count();
if (totalCount <= _indicatorView.MaximumVisible)
{
return itemsSource;
}
// If the source is a collection, we can use Count to determine whether filtering is necessary
if (itemsSource is ICollection col)
{
if (col.Count <= _indicatorView.MaximumVisible)
{
return itemsSource;
}
var filteredFromCollection = new List<object>(_indicatorView.MaximumVisible);
foreach (var item in itemsSource)
{
if (filteredFromCollection.Count >= _indicatorView.MaximumVisible)
{
break;
}
filteredFromCollection.Add(item);
}
return filteredFromCollection;
}
// For non-ICollection sources, avoid double enumeration by building the filtered list in a single pass

Copilot uses AI. Check for mistakes.
Comment on lines +2 to +5
*REMOVED*~static readonly Microsoft.Maui.Controls.Handlers.Compatibility.ShellRenderer.DefaultForegroundColor -> Microsoft.Maui.Graphics.Color
*REMOVED*~static readonly Microsoft.Maui.Controls.Handlers.Compatibility.ShellRenderer.DefaultTitleColor -> Microsoft.Maui.Graphics.Color
~static Microsoft.Maui.Controls.Handlers.Compatibility.ShellRenderer.DefaultForegroundColor.get -> Microsoft.Maui.Graphics.Color
~static Microsoft.Maui.Controls.Handlers.Compatibility.ShellRenderer.DefaultTitleColor.get -> Microsoft.Maui.Graphics.Color
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

This changes public API shape on Android from static readonly fields to properties. That’s a breaking change for consumers referencing the fields. If this is shipping in a minor/service release, it should be avoided (keep the fields and add new properties, or keep binary compatibility via obsolete forwarders if possible).

Copilot uses AI. Check for mistakes.
TamilarasanSF4853 and others added 3 commits March 25, 2026 17:22
<!-- 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 Detail
The fix for #30181 (PR #30540) introduced a regression where valid
numeric strings starting with "0" — such as "0.5" (en-US) and "0,5"
(pt-PT) — were incorrectly blocked from converting to double in
BindingExpressionHelper.TryConvert. This caused Slider.Value to remain
at its default 0.0 instead of the expected bound value.

### Root Cause
PR #30540 added StartsWith("0") to the conversion guard:
StartsWith("0") matched any string beginning with 0, including valid
complete values like "0.5" and "0,5", blocking their conversion
entirely.

### Description of Change
Narrowed the guard to only block "-0..." strings that parse to exactly
0.0 — the genuine negative-zero intermediate typing state (e.g., -0,
-0.0):
This preserves the fix for #30181 while allowing valid complete values
to convert normally.

### Test Fixed:

- ConvertIsCultureAware 
- Convert
…: RightToLeft) device tests (#34645)

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

### Issue Details
This PR #30653 causes [WebView] FlowDirection is set
correctly(flowDirection: RightToLeft) device tests was failed.


### Description of Change

<!-- Enter description of the fix in this section -->
The root cause is that MapFlowDirection only updated the internal
UIScrollView of WKWebView, but not the WKWebView itself. Since the test
reads SemanticContentAttribute directly from the WKWebView platform
view, it always returned LeftToRight regardless of the set value. So
updated the WebView FlowDirection as well.

### Test fixed
* [WebView] FlowDirection is set correctly(flowDirection: RightToLeft)
### Issue Details:
This PR  #30339 caused the NavBarIsVisibleUpdates unit test to fail.

### Description of Changes:
In the test case, the NavBarIsVisible property value was cleared, but
that scenario was not handled in the PR #30339 . I have updated the fix
to address this case. With the current changes, both the test failure
and the original issue are resolved.

### Test fixed 
* NavBarIsVisibleUpdates
Reverts 7ddc0a1, 49e9512, 117fd00, ca29f7a, 492769c which were
accidentally cherry-picked onto inflight/candidate. These fix commits
belong on the fix-34635 feature branch only.
Shalini-Ashokan and others added 2 commits March 26, 2026 14:38
…ute changes (#34668)

<!-- 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
This PR #28734 causes the unit test below

1. BackButtonUpdatesWhenSetToNewCommand
2. BackButtonDisabledWhenCommandDisabled

### Description of Change

The root cause is [IsEnabledCore { set => SetValue(IsEnabledProperty,
value && IsEnabled);
}](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
— a circular read: once
[IsEnabledProperty](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
is false, reading
[IsEnabled](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
always returns false, so the property is permanently stuck.

The fix introduces two backing fields to track the concerns
independently:

-
[_userDefinedIsEnabled](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
— written only by the developer via
[IsEnabled](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
-
[_commandEnabled](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
— written only by
[CanExecute](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
via
[IsEnabledCore](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
-
[IsEnabledProperty](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
is always [_userDefinedIsEnabled &&
_commandEnabled](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html),
eliminating the circular read.

- BackButtonDisabledWhenCommandDisabled — When
[CanExecute](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
flips to true and
[ChangeCanExecute()](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
is called,
[_commandEnabled](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
updates correctly and the back button re-enables.

- BackButtonUpdatesWhenSetToNewCommand — Setting [Command =
null](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
resets [_commandEnabled =
true](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html),
so the back button re-enables as expected.


### Test fixed
Unit tests:
BackButtonUpdatesWhenSetToNewCommand
BackButtonDisabledWhenCommandDisabled
…ice tests (#34674)

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

### Issue Details
This PR #32878 caused the NavigatingAwayFromTabbedPageResizesContentPage
device tests to failed in Candidate branch.


### Description of Change

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

In the device test NavigatingAwayFromTabbedPageResizesContentPage, the
height of the new ContentPage is validated. Due to the changes in PR
#32878, an incorrect page height was returned, causing the test to fail.

In TabbedPageManager, reintroduced RemoveTabs(). For modal navigation,
an early return is applied (similar to PR #32878).

With these changes, both issue
CommunityToolkit/Maui#2708 and the candidate
test failures are resolved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.