Conversation
… 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"/>|
…ork in CollectionView after scroll - fix (#28151) ### Issues Fixed Fixes #28147 |Before|After| |--|--| |<video src="https://github.com/user-attachments/assets/09a75432-4b03-465a-910d-844076f18548" width="300px"/>|<video src="https://github.com/user-attachments/assets/29d23e8c-6eaf-45c0-a6ed-e90ffc089c52" 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"> |
…nce customization (#27848) ### Issues Fixed Fixes #27846 Fixes #26975 |Before|After| |--|--| |<video src="https://github.com/user-attachments/assets/d7215924-10c5-487d-9e00-d170aab4715c" width="300px"/>|<video src="https://github.com/user-attachments/assets/ccd8f6ac-f305-4f3b-b423-e9fb9285bce4" width="300px"/>|
…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>
…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.
<!-- 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
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34617Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34617" |
There was a problem hiding this comment.
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) => { }; |
There was a problem hiding this comment.
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.
| public void Dispose() | ||
| { | ||
| Controls.Internals.ResourceLoader.ExceptionHandler2 = null; | ||
| } |
There was a problem hiding this comment.
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.
| bool exceptionThrown = false; | ||
| try | ||
| { | ||
| page.LoadFromXaml(xaml); | ||
| } | ||
| catch (Exception) | ||
| { | ||
| exceptionThrown = true; | ||
| } | ||
|
|
||
| Assert.True(exceptionThrown, "Expected an exception to be thrown for missing ControlTemplate"); |
There was a problem hiding this comment.
Prefer asserting exceptions directly (e.g., Assert.Throws<...>(() => ...)) instead of a boolean flag. This produces clearer failure output and avoids masking unintended exception types.
| 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)); |
| var handler = CreateHandler<SearchBarHandler>(searchBar); | ||
| var platformControl = GetPlatformControl(handler); |
There was a problem hiding this comment.
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.
| if (platformControl is UIKit.UISearchBar uiSearchBar) | ||
| { | ||
| actualWidth = uiSearchBar.Frame.Width; | ||
| } | ||
|
|
||
| Assert.Equal(requestedWidth, actualWidth); |
There was a problem hiding this comment.
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.
|
|
||
| // 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)) |
There was a problem hiding this comment.
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.\").
| // Get the filtered items source based on MaximumVisible | ||
| var itemsSource = GetFilteredItemsSource(); | ||
| BindableLayout.SetItemsSource(this, itemsSource); |
There was a problem hiding this comment.
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.
| var filteredItems = new List<object>(_indicatorView.MaximumVisible); | ||
| foreach (var item in itemsSource) | ||
| { | ||
| if (filteredItems.Count >= _indicatorView.MaximumVisible) | ||
| { | ||
| break; | ||
| } | ||
|
|
||
| filteredItems.Add(item); | ||
| } |
There was a problem hiding this comment.
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.
| int totalCount = itemsSource is ICollection col | ||
| ? col.Count | ||
| : itemsSource.Cast<object>().Count(); | ||
|
|
||
| if (totalCount <= _indicatorView.MaximumVisible) | ||
| { | ||
| return itemsSource; | ||
| } | ||
|
|
There was a problem hiding this comment.
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().
| 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 |
| *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 |
There was a problem hiding this comment.
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).
This PR removes the APIs that were added in this commit: https://github.com/dotnet/maui/pull/33600/changes#diff-c710daaba40199243111fcb8a8d5185e939c757b00785b0780d5217c8cf757e5 during rebase. Was this API already removed in this revert PR 508d5c8#diff-c710daaba40199243111fcb8a8d5185e939c757b00785b0780d5217c8cf757e5. Fixes: #34617
<!-- 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
…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.
No description provided.