You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A recent product update has been released that may impact our documentation. This could include new features, changes to existing functionality, or other product enhancements. Your Action Required: Please review the suggestions below and update the relevant documentation to ensure accuracy and completeness.
Multiple .NET MAUI Controls now avoid common memory leaks caused by strong event subscriptions by switching to weak-subscription patterns, so long-lived ICommand, ObservableCollection/INotifyCollectionChanged, or shared/long-lived Span instances no longer keep discarded controls alive (no public API change unless noted):
ListView.RefreshCommand uses WeakCommandSubscription for CanExecuteChanged.
Shell BackButtonBehavior.Command/CommandParameter routes CanExecuteChanged via ICommandElement/WeakCommandSubscription.
IndicatorView.ItemsSource uses a weak collection-changed proxy (WeakNotifyCollectionChangedProxy) and adds a new public finalizer IndicatorView.~IndicatorView() to ensure proxy unsubscription during finalization.
TableView/TableRoot/TableSection internal change notifications use weak-event patterns so shared/long-lived roots/sections don’t retain dropped TableViews.
GeometryGroup.Children uses weak collection/property proxies (WeakNotifyCollectionChangedProxy / WeakNotifyPropertyChangedProxy) and rendering now treats Children == null as empty and skips null entries in Children across flattening/conversion paths.
GradientBrush.GradientStops now correctly tracks/releases GradientStop.PropertyChanged for all NotifyCollectionChangedAction cases, including Reset (Clear() with OldItems == null), preventing lingering subscriptions.
FormattedString (often via Label.FormattedText) uses per-occurrence weak subscriptions to shared Span.PropertyChanging/PropertyChanged, so shared spans don’t keep discarded FormattedStrings alive.
XAML binding diagnostics BindingDiagnostics.BindingFailed is now backed by WeakEventManager, so subscribers may stop receiving events once GC’d unless the app keeps a strong reference.
.NET MAUI Android safe-area / insets / RTL layout behavior was corrected in multiple scenarios:
SafeAreaEdges=None is now honored when hiding the navigation bar (eliminates the blank top gap from stale AppBarLayout padding).
RTL child arrangement now mirrors within the padded content box ([PaddingLeft, Width - PaddingRight]) so asymmetric safe-area padding/cutout insets don’t shift/truncate RTL content.
During IME (soft keyboard) animations, views that (re)attach mid-animation can receive one valid inset dispatch immediately (instead of staying at zero padding until animation end), and settled insets are guaranteed to reapply at animation end.
For translated views, the “full-screen Shell navigation transition” top-inset heuristic now only triggers when the translated view actually covers the usable screen, so smaller translated controls (e.g., bottom sheets) don’t retain extra top padding.
.NET MAUI ScrollView on iOS/Mac Catalyst has several user-visible scrolling/offset and ScrollToAsync behavior changes:
Breaking:ScrollX/ScrollY and ScrolledEventArgs offsets are now content coordinates (viewport top-left is (0,0)) rather than raw UIScrollView.ContentOffset, aligning with Android; “rest” offset is now 0 (not -AdjustedContentInset.Top). ScrollToAsync clamping/targeting is AdjustedContentInset-aware, inset-only changes update offsets without raising Scrolled, and deferred ScrollToAsync cases (pre-handler or before layout) reliably complete once layout is ready.
Element-mode ScrollToAsync / ScrollToRequested requests are now parked until valid layout geometry exists (including when target is in a collapsed/hidden branch) and are only completed by replaying after arrange or by being dropped (task completes without scrolling) when the handler disconnects, the ScrollView is removed from the visual tree, or the target becomes orphaned; also prevents stale replays from overriding newer scroll requests.
On iOS/Mac Catalyst, ScrollViewHandler.PlatformArrange(Rect) now preserves (and clamps) UIScrollView.ContentOffset during arrange when the parent resizes the ScrollView; this is a new public override surface, and custom handlers should call base.PlatformArrange(rect) to keep the offset-preservation behavior.
Shell (Compatibility) ShellFlyoutLayoutManager (iOS) for FlyoutHeaderBehavior.Scroll now uses native UIScrollView.ContentOffset (not ScrollView.ScrollY) to avoid header collapse/position mismatches when flyout content is a ScrollView.
.NET MAUI iOS 26+ keyboard “Done” accessory UX changed: the accessory is now a pass-through container with a floating 44×44 “xmark” glass button (taps on transparent area pass through), accessory height remains 44 points, it exposes accessibility identifier "DoneAccessory" (with localized “Done” accessibility label), the button was later positioned 4 points higher, and an AppContext switch "Microsoft.Maui.Platform.iOS.UseLegacyDoneAccessory" (default-off, must be set before creating MAUI controls; cached per accessory instance) can restore the legacy full-width UIToolbar behavior.
In .NET MAUI Button on iOS/Mac Catalyst, several text/layout updates are now observable:
Changing Button.Text reliably refreshes CharacterSpacing (kerning) after the native UIButton text update, including TextTransform and ContentLayout scenarios.
When CharacterSpacing is set (attributed title), runtime TextColor updates now also update/remove the attributed-title ForegroundColor so visible text color changes correctly (including when TextColor resets to null).
Button.UpdateBackground no longer forces BackgroundColor = UIColor.Clear during initial render while UIButton.Window is null, preserving background set by custom UIButton subclasses until attachment (while still clearing later when paint becomes null).
ContentLayout with ButtonContentLayout.ImagePosition.Left/Right now respects RTL (FlowDirection.RightToLeft) when laying out image+text, preserving configured spacing and preventing overlap/excess separation.
.NET MAUI CollectionView / CarouselView behavioral fixes across platforms (selection/scrolling/layout/empty-state):
(CV2 iOS/Mac Catalyst) Empty CollectionViews with no items and no EmptyView now collapse to zero in the scroll direction instead of using an expansive fallback desired size; includes a handler safeguard to force a temporary layout pass when native UICollectionView frame is still zero after transitioning from empty to non-empty.
(Items2 iOS) When empty, the EmptyView is now kept as a subview of the native UICollectionView (not inserted above it), fixing a case where pull-to-refresh via RefreshView didn’t work because the empty view intercepted pan gestures; RTL is preserved by applying FlowDirection to the empty-view content while counter-transforming the empty-view host, and transforms are reset before setting frames to avoid UIKit “undefined Frame under transform” issues.
(Grouped CollectionView iOS) Group/section removal after INotifyCollectionChanged.Remove is now handled correctly by avoiding a premature UpdateSection call until after DeleteSections reconciles the already-mutated grouped source.
(Grouped CollectionView + GridItemsLayout) Grouped grid spacing/rendering is more consistent: Windows item containers are vertically stretched so the first item in the first group no longer collapses when a group header affects row height; iOS/Mac Catalyst grouped grid sections now apply header/footer boundary spacing and InterSectionSpacing based on main-axis item spacing so headers don’t visually touch the first row.
(CarouselView/CarouselView2 Items2) IsSwipeEnabled and IsBounceEnabled are applied consistently across Android/iOS/Mac Catalyst (including reapplication during layout / when UIKit creates/updates embedded orthogonal UIScrollView); on Android, touch dispatch now honors IsSwipeEnabled so the carousel can’t still scroll when swipe is disabled.
(CarouselView iOS/Mac Catalyst) Position, CurrentItem, and IndicatorView stay in sync across handler detach/reattach: if Position changes while detached, reattachment restores to that Position (instead of always restoring based on CurrentItem), while preserving existing CurrentItem-based restore behavior for collection mutation scenarios; teardown cancels iOS scroll debounce work and ignores callbacks when CurrentItem resolves to an invalid index to prevent post-detach scrolls/position drift (notably observed on iOS 26).
(CarouselView iOS) After an off-screen/detached ItemsSource replacement, a newly set CurrentItem is now honored (avoids stale Position overriding intended item on reattach).
(CarouselView Android) INotifyCollectionChanged.Replace is handled as a dedicated path: when Loop="False" selection is preserved (no reset to first item); when Loop="True" only visible looped cells are rebound to show the replaced value without full adapter rebuild; includes guards/clamping to avoid teardown-race null issues and invalid ScrollToPosition(-1) errors.
(Mac Catalyst CollectionView/CarouselView) Scroll position is preserved after window-state changes (e.g., dismissing a Picker, resizing, minimize/restore) that previously caused contentOffset clamps; restore is armed after non-animated programmatic scrolls and canceled on user drag or ItemsSource/layout changes (Y-axis contentOffset KVO monitoring), with new Mac Catalyst public override surfaces for lifecycle/interaction handling.
(iOS/Mac Catalyst) HtmlWebViewSource navigation (MauiWKWebView.LoadHtml) uses WKWebView.LoadSimulatedRequest on iOS 15+/Mac Catalyst 15+ so HTML pages are added to history and WebView.GoBack()/GoForward() work after HtmlWebViewSource navigation; iOS 13/14 continues to use LoadHtmlString, baseUrl/bundle-path origin behavior remains consistent, and HTML content is not exposed via WKWebView.Url (only base URL is reflected).
(Android WebView + BlazorWebView) Android WebView now explicitly sets WebView.Settings.MinimumFontSize and MinimumLogicalFontSize to 1, preventing default minimum font sizes (often 8px) from clamping small CSS font-size values.
(Android BlazorWebView) Blazor Hybrid startup/JS bridge initialization is now idempotent and waits for a native WebMessagePort delivered via a 'capturePort' window message before calling Blazor.start(), sets window.__BlazorStarted only after the Blazor.start() promise resolves, and filters dispatched messages so only native PostWebMessage events with event.source === null are forwarded.
(Android BlazorWebView) External URL handling sanitizes intent:// and android-app:// by creating the Intent via CreateIntentForExternalUri that forces CATEGORY_BROWSABLE, clears explicit component/selector, and masks flags to an allowlist (can change which apps can be launched vs Intent.ParseUri(..., Scheme)).
(HybridWebView) JavaScript messaging now validates message origin on Windows (WebView2) and iOS (WKWebView): messages are ignored (debug log only) unless args.Source / message.FrameInfo.Request.Url is an absolute URI under the handler’s AppOriginUri.
(Windows WebView) Breaking:https://appdir/ virtual host mapping is now treated as local appdir content only when the parsed absolute URI is HTTPS, has no userinfo, and host is exactly appdir (case-insensitive), and appdir mapping is cleared on navigation to non-appdir hosts; additionally, appdir mapping now uses CoreWebView2HostResourceAccessKind.DenyCors (was Allow), so cross-origin fetch/XHR to https://appdir/... is no longer allowed (while normal sub-resources and same-origin fetch from a real https://appdir/ page loaded via LoadUrl still work).
SearchHandler.ShowsResults now updates the search results UI dynamically at runtime across Android (dropdown/filtering threshold behavior), iOS/Mac Catalyst (recreates UISearchController when ShowsResults changes while preserving current query text), and Windows (AutoSuggestBox.ItemsSource toggled to null when results disabled and resynchronized when re-enabled, including when ItemsSource changes).
(Windows Shell SearchHandler) SearchHandler.FontFamily, FontSize, and FontAttributes are now applied to the native AutoSuggestBox on attach and when changed (previously ignored).
(Android Shell) Default flyout menu item label TextColor is no longer applied via an internal class style that blocked user styles; default is applied directly to the generated Label at the lowest specificity so user-provided styling (implicit Style TargetType="Label" and explicit/class styles like Class="FlyoutItemLabelStyle") reliably overrides it, matching iOS/Windows behavior.
.NET MAUI Windows UI/handler behavior fixes and observable changes:
Layouts with InputTransparent="True" (or handler hit-test behavior) and non-null Background no longer lose their visible background color; Windows LayoutPanel now renders a non-hit-testable background layer behind children.
Handler mapper updates are skipped after the MauiContext window scope is disposed (tracked via internal MauiContext.IsWindowScopeDisposed), preventing shutdown-time ObjectDisposedException (e.g., focus loss triggering mapper work during window close).
Fullscreen modal navigation no longer reserves title-bar height: when a modal page is pushed while in AppWindowPresenterKind.FullScreen, MAUI suppresses the title-bar height reservation (eliminates ~32px gap and restores pointer/mouse interactivity in the top area), updates dynamically on entering/exiting full-screen while modal is visible, and respects explicit Window.TitleBar / TitleBar.IsVisible.
Border stroke line-cap mapping now also applies to dashed strokes (Path.StrokeDashCap set alongside StrokeStartLineCap/StrokeEndLineCap) so StrokeLineCap affects dashed borders as expected.
Placing a SwipeView (WinUI SwipeControl) directly inside a Border no longer crashes WinUI; ContentPanel.UpdateClip skips applying a geometric clip to SwipeControl (border stroke still renders, but SwipeView content/corners won’t be clipped to the Border shape in this scenario).
Image.BackgroundColor/IImage.Background updates via data binding no longer crash with a COMException when the Image has been unloaded and a bound value changes from null to a color; background/container creation is deferred until the native Image is IsLoaded (applies when re-entering the visual tree).
.NET MAUI Label.FormattedText / formatted text behavior updates across platforms:
(iOS/Mac Catalyst) Span hit-testing for TapGestureRecognizer now aligns hitboxes with rendered text for custom fonts that include an OpenType STAT table; on iOS 16+ NSLayoutManager.UsesFontLeading is disabled to match CoreText line metrics, and span-rect calculation prefers MAUI’s arrange finalSize over UILabel.Bounds (which can be stale/zero during layout).
(iOS/Mac Catalyst) FormattedText now honors RTL by using EffectiveFlowDirection, setting NSParagraphStyle.BaseWritingDirection, mirroring TextAlignment.Start/End, and changing IView.FlowDirection at runtime triggers a rebuild so paragraph direction/alignment don’t go stale.
(Windows) Updating Label.FormattedText clears WinUI TextBlock.TextHighlighters when rebuilding inlines so old highlight/background ranges don’t persist onto new formatted text.
(Windows) FormattedText no longer risks UI-thread hangs and eventual OutOfMemoryException when created/updated while hidden (collapsed) and later shown; span-position recalculation now guards against zero/negative measured line heights to avoid an infinite layout loop.
.NET MAUI input controls / keyboard and back-button behavior fixes:
ContentPage.HideSoftInputOnTapped (Android/iOS) is now determined only by the currently focused input’s enclosing ContentPage (via live Element.Parent chain with a fallback to cached enclosing page while focus remains), fixing a “sticky” case where a previously navigated/hidden page could keep the behavior effectively enabled for subsequent pages.
Entry password behavior (iOS/Windows): Keyboard="Password" no longer forces masking when IsPassword="False"—IsPassword is now respected on initial load (iOS+Windows) and when toggled at runtime (Windows).
(Windows Entry) Entry.Completed is no longer raised when the user presses Enter to confirm a Chinese/Japanese IME candidate; Completed now fires only on Enter KeyUp if a matching Enter KeyDown was observed (reset on focus loss).
(iOS/Mac Catalyst Entry) With ClearButtonVisibility enabled and TextColor set, the built-in clear button (✕) now tints at full opacity to match TextColor instead of rendering dim/faded.
(Android Entry) Keyboard="Numeric" and similar non-password input types no longer clear password-variation bits unless actually present, restoring the ability to input the OS-locale decimal separator.
Back navigation routing (Window / Page.OnBackButtonPressed) now detects when a page overrides OnBackButtonPressed and ensures the override always receives the back press instead of relying solely on container/navigation-state heuristics.
.NET MAUI iOS/Mac Catalyst handler mappings for Background clearing and updates were corrected/expanded:
Image/ImageButton background mapping now truly clears rendered background when set to null/empty (removes background layer and resets native background color), including support for ImageSourcePaint backgrounds; Image also reapplies IView.Opacity after background changes to avoid compounded opacity when containers/wrappers transition.
DatePicker and TimePicker now correctly clear the native background when Background is set to null at runtime (remove background layer and reset BackgroundColor), aligning iOS/Mac behavior with documented Background behavior.
SwipeView / SwipeItem now updates swipe-item background on app theme changes (e.g., AppThemeBinding on SwipeItem.BackgroundColor) by triggering handler background updates and fixing property mapping to ISwipeItemMenuItem.Background; on iOS and Windows, background updates also re-apply ITextStyle.TextColor.
(Android accessibility) Revealed SwipeItem / SwipeItemView commands can now be activated via TalkBack (ACTION_CLICK / double-tap to activate); SwipeBehaviorOnInvoked (e.g., auto-close vs RemainOpen) is still honored.
(Android layout) Swipe item measurement changed: width stays Exactly for default items (to keep text visible), but height is now always measured with AtMost so buttons can self-size and keep icon+text vertically centered (may change sizing vs prior releases).
.NET MAUI FlexLayout fixes: measurement was adjusted so children aren’t measured against full container size when margins/fixed cross-axis sizing mean the view will be arranged narrower (fixes word-wrap cases where last line could be clipped), and on Windows post-detach layout/measure calls are safely ignored (avoids NRE crashes in virtualized templates) with detached measure/frame queries returning zero sizes/rects.
.NET MAUI XAML C# expressions / SourceGen diagnostics and expression support updates:
XEXPR/XAML compilation diagnostics catch more invalid expressions at generation time: MAUIX2009 now validates identifiers inside interpolated string holes; MAUIX2017 reports lambda bodies that are method-group references instead of invocations; member-not-found diagnostics are suppressed when expression begins with a resolvable static type reference.
New x:Code validation diagnostics: MAUIX2015 when x:Code is not an immediate child of the root element; MAUIX2016 when x:Code is used without x:Class on the root element.
Source generation supports setters for struct (value-type) sub-property paths like {Margin.Top} via copy–modify–writeback; when a struct intermediate property has no public setter and the binding is TwoWay (or TwoWay-by-default), the generator omits the setter (binding becomes effectively one-way) and emits the StructIntermediateNotSettable warning, whose diagnostic ID changed from MAUIX2017 to MAUIX2018.
XAML C# expressions now support type references via XAML xmlns prefixes inside {...} expressions and attached bindable property reads via target-qualified target.(Type.Property) / this.(Type.Property) rewritten to Type.GetProperty(target); the standalone {(Type.Property)} form is explicitly rejected with a diagnostic instructing authors to use this.(...) or element.(...) (no two-way setters or ABP change-notification support is generated).
.NET MAUI build/tooling updates that may affect troubleshooting, scripts, or single-project resource guidance:
BindingSourceGen now emits short deterministic hashed hint names (e.g., BindingSourceGen-{stableHash}-{line}-{column}.g.cs) instead of embedding full source file paths, changing emitted generated filenames when EmitCompilerGeneratedFiles is enabled and preventing Windows MAX_PATH failures.
Resizetizer targets ensure MauiFont and MauiSplashScreen assets are reliably included on first build and after deleting obj: font collection is moved to always-run _CollectMauiFontItems, and incremental tracking switches from stamp files to output manifests (mauifont.outputs, mauisplash.outputs) so missing outputs re-trigger only affected targets; iOS/Mac Catalyst font registration de-duplicates colliding font filenames and deletes stale MauiInfo.plist when the last MauiFont is removed.
MAUI build tasks now reference Mono.Cecil 0.11.6 (from 0.11.5) to incorporate an upstream fix that prevents corruption of generated PDBs.
MAUI integrates SkiaSharp 4.150.1 and updates related SVG processing dependencies (e.g., Svg.Skia 5.1.1); may affect apps that directly reference SkiaSharp alongside MAUI.
.NET MAUI templates and Apple lifecycle behavior changes:
dotnet new maui mobile template with --sample-content: generated MainPageModel.InitData() no longer calls Refresh(), so initial startup loads once (initial refresh remains triggered from Appearing()), avoiding duplicate refresh/data loading.
dotnet new app templates for iOS and Mac Catalyst now default to UIKit’s scene-based lifecycle by adding a UIApplicationSceneManifest + a SceneDelegate deriving from Microsoft.Maui.MauiUISceneDelegate (with UIApplicationSupportsMultipleScenes=false and required configuration name __MAUI_DEFAULT_SCENE_CONFIGURATION__), and these templates raise the default Mac Catalyst SupportedOSPlatformVersion to 17.0 (macOS 14).
iOS/Mac Catalyst Quick Actions lifecycle registrations (iOSLifecycle.PerformActionForShortcutItem) must now invoke completionHandlerexactly once; MAUI aggregates multiple handlers and completes the native callback after handlers return and either one reports true or all report false. New public override point: MauiUISceneDelegate.PerformAction(UIWindowScene, UIApplicationShortcutItem, Action<bool>). Essentials AppActions on iOS reports handled=false on exceptions before rethrowing and only returns handled=true when AppActionActivated has subscribers.
Essentials MauiAppBuilder.ConfigureEssentials on iOS forwards scene-based authentication callbacks (SceneOpenUrl and SceneContinueUserActivity for WebPageUrl) to WebAuthenticator.Default for scene-based lifecycle apps (forwarding is limited to WebAuthenticator handling and does not replay cold-connection URLs/activities only available via SceneWillConnect).
dotnet new maui-mobile template (Android/TalkBack): TaskDetailPage/ProjectDetailPage now apply accessibility text to the interactive Picker controls using SemanticProperties.Hint (instead of setting SemanticProperties.Description on a non-interactive wrapper), fixing TalkBack navigation so users can reach/activate the pickers and continue to subsequent controls.
maui-mobile template: ComboBox SemanticProperties.Hint text updated to include an initial “State Collapsed” hint to improve macOS VoiceOver announcement of initial collapsed/expanded state.
.NET MAUI Essentials and platform utilities behavior updates:
Essentials Permissions.RequestAsync<T>() on Android validates MainThread.IsMainThread before registering request code (and cleans up if ActivityCompat.RequestPermissions throws), so repeated background-thread calls still throw PermissionException but won’t poison later valid main-thread prompts with “same key has already been added”.
Essentials Screenshot.Default.CaptureAsync() on Android avoids deadlocks when callers synchronously block on the UI thread by dispatching the PixelCopy completion callback on a dedicated HandlerThread and using ConfigureAwait(false); if PixelCopy fails off the main thread, capture now returns failure (null) instead of attempting view-based fallbacks off the UI thread.
Essentials (iOS/tvOS/watchOS) fixes sysctlbyname P/Invoke signature to use size_t-sized parameters (nuint and ref nuint), reducing unexpected InvalidOperationException failures when reading system properties.
Essentials MediaPicker on Android (Photo Picker path) now requires the current Activity to be an AndroidX.Activity.ComponentActivity and requires calling Microsoft.Maui.ApplicationModel.Platform.Init(Activity, Bundle) in OnCreate; otherwise throws InvalidOperationException with explicit guidance. The Android activity-result infrastructure was redesigned so activity-result launchers and pending requests are tracked per-ComponentActivity instance (with instance-state persistence and lifecycle cleanup), enabling multiple activities to use MediaPicker independently and avoiding clobbered/hung requests across recreation/concurrent launches.
Essentials MediaPicker on iOS no longer throws UIKitThreadAccessException when picking multiple items (2+), by capturing each PHPickerResult.ItemProvider on the main thread before any await.
Essentials Accelerometer.ReadingChanged and ShakeDetected were changed to a weak-subscription model and then reverted back to standard .NET event semantics; the final behavior is standard C# events (handlers are held strongly, and apps should unsubscribe with -= to avoid retaining subscribers).
SemanticProperties.Description is now always mapped to the native Android accessibility node’s ContentDescription for all views including Entry/EditText (previously Entry only injected description into node Text); synthesized editable control text behavior is preserved (e.g., ContentDescription = description, Text = “description, entry text”).
Android Picker platform views restore horizontal drag scrolling for long selected values by delegating touch events to ScrollingMovementMethod while keeping DefaultMovementMethod null (read-only, no cursor/text selection), cancel click/press when a drag exceeds touch slop, and disable long-click (LongClickable = false).
Release-readiness automation/docs updates in .github/skills/release-readiness: adds New-ReleaseHandoff.ps1 + references/release-handoff.md to generate deterministic public-safe Preview/SR handoff outputs (validates/omits non-public URLs and sensitive data; requires explicit PublicEvidence: true in evidence JSON), updates PreviewInstallability.ps1 to generate isolated NuGet config with packageSourceMapping and a prior-major compatibility feed for .NET majors > 8, updates the skill docs to reflect the new workflows, and Get-PreviewReadiness.ps1 adds optional local net11 internal “official build health” enrichment that is emitted only when -PublicSafe:$false and always skipped on GitHub Actions.
Instructions for Copilot: Copilot should only fix suggestions with a checkmark and do not make any updates for unchecked suggestions.
Note
Suggestions are generated by AI and they should be reviewed by human before assigning it to Copilot. Please uncheck the ones you don't want Copilot to work on. Then assign this issue to Agent (GitHub Copilot).
[Improvements] Add an explicit note/warning in the sections that describe JavaScript-to-.NET messaging (at minimum: the intro description of HybridWebView communication, the “Invoke C# from JavaScript” section, and the JavaScript library section showing WebView2/WKWebView message plumbing) stating that on Windows (WebView2) and iOS (WKWebView) HybridWebView validates message origin and will ignore messages unless the sender’s source URL is an absolute URI under the handler’s AppOriginUri; calls may fail silently (debug log only) when content is navigated off-origin or messages originate from non-app-origin frames.
[Correction Required] Update the “Create a new project” section’s project file examples (both the library project snippet and the platform project snippet) so the demonstrated TargetFramework/TargetFrameworks values match the current .NET MAUI multi-project template output for .NET MAUI 10 (instead of showing net8.0*/.NET 8 TFMs). This prevents users from incorrectly editing TFMs to match outdated examples and ending up with a non-building or incorrectly targeted MAUI 10 project.
[Correction Required] In the "Semantic properties" > "Description" section, update the Warning bullet that says to avoid setting SemanticProperties.Description on an Entry or Editor on Android because it stops TalkBack actions. This warning must be removed or revised to reflect the current Android behavior where Description maps to the accessibility node ContentDescription for Entry/EditText without breaking editable control behavior, so readers are not misled about supported usage.
The source content behind this signal has been updated, so this issue has been superseded by #3560 and is being closed automatically. No pull request was linked to it.
Background
A recent product update has been released that may impact our documentation. This could include new features, changes to existing functionality, or other product enhancements.
Your Action Required: Please review the suggestions below and update the relevant documentation to ensure accuracy and completeness.
Signal Details:
Source Signal Summary
Details
ICommand,ObservableCollection/INotifyCollectionChanged, or shared/long-livedSpaninstances no longer keep discarded controls alive (no public API change unless noted):SwipeItemView.Command(SwipeView) usesWeakCommandSubscriptioninstead ofCommand.CanExecuteChanged += ...(preservingIsEnabled/CanExecutebehavior).ListView.RefreshCommandusesWeakCommandSubscriptionforCanExecuteChanged.BackButtonBehavior.Command/CommandParameterroutesCanExecuteChangedviaICommandElement/WeakCommandSubscription.IndicatorView.ItemsSourceuses a weak collection-changed proxy (WeakNotifyCollectionChangedProxy) and adds a new public finalizerIndicatorView.~IndicatorView()to ensure proxy unsubscription during finalization.TableView/TableRoot/TableSectioninternal change notifications use weak-event patterns so shared/long-lived roots/sections don’t retain droppedTableViews.GeometryGroup.Childrenuses weak collection/property proxies (WeakNotifyCollectionChangedProxy/WeakNotifyPropertyChangedProxy) and rendering now treatsChildren == nullas empty and skips null entries inChildrenacross flattening/conversion paths.GradientBrush.GradientStopsnow correctly tracks/releasesGradientStop.PropertyChangedfor allNotifyCollectionChangedActioncases, includingReset(Clear()withOldItems == null), preventing lingering subscriptions.FormattedString(often viaLabel.FormattedText) uses per-occurrence weak subscriptions to sharedSpan.PropertyChanging/PropertyChanged, so shared spans don’t keep discardedFormattedStrings alive.BindingDiagnostics.BindingFailedis now backed byWeakEventManager, so subscribers may stop receiving events once GC’d unless the app keeps a strong reference.SafeAreaEdges=Noneis now honored when hiding the navigation bar (eliminates the blank top gap from staleAppBarLayoutpadding).[PaddingLeft, Width - PaddingRight]) so asymmetric safe-area padding/cutout insets don’t shift/truncate RTL content.ScrollViewon iOS/Mac Catalyst has several user-visible scrolling/offset andScrollToAsyncbehavior changes:ScrollX/ScrollYandScrolledEventArgsoffsets are now content coordinates (viewport top-left is(0,0)) rather than rawUIScrollView.ContentOffset, aligning with Android; “rest” offset is now0(not-AdjustedContentInset.Top).ScrollToAsyncclamping/targeting isAdjustedContentInset-aware, inset-only changes update offsets without raisingScrolled, and deferredScrollToAsynccases (pre-handler or before layout) reliably complete once layout is ready.ScrollToAsync/ScrollToRequestedrequests are now parked until valid layout geometry exists (including when target is in a collapsed/hidden branch) and are only completed by replaying after arrange or by being dropped (task completes without scrolling) when the handler disconnects, theScrollViewis removed from the visual tree, or the target becomes orphaned; also prevents stale replays from overriding newer scroll requests.ScrollViewHandler.PlatformArrange(Rect)now preserves (and clamps)UIScrollView.ContentOffsetduring arrange when the parent resizes theScrollView; this is a new public override surface, and custom handlers should callbase.PlatformArrange(rect)to keep the offset-preservation behavior.ShellFlyoutLayoutManager(iOS) forFlyoutHeaderBehavior.Scrollnow uses nativeUIScrollView.ContentOffset(notScrollView.ScrollY) to avoid header collapse/position mismatches when flyout content is aScrollView."DoneAccessory"(with localized “Done” accessibility label), the button was later positioned 4 points higher, and an AppContext switch"Microsoft.Maui.Platform.iOS.UseLegacyDoneAccessory"(default-off, must be set before creating MAUI controls; cached per accessory instance) can restore the legacy full-widthUIToolbarbehavior.Buttonon iOS/Mac Catalyst, several text/layout updates are now observable:Button.Textreliably refreshesCharacterSpacing(kerning) after the nativeUIButtontext update, includingTextTransformandContentLayoutscenarios.CharacterSpacingis set (attributed title), runtimeTextColorupdates now also update/remove the attributed-titleForegroundColorso visible text color changes correctly (including whenTextColorresets tonull).Button.UpdateBackgroundno longer forcesBackgroundColor = UIColor.Clearduring initial render whileUIButton.Windowisnull, preserving background set by customUIButtonsubclasses until attachment (while still clearing later when paint becomes null).ContentLayoutwithButtonContentLayout.ImagePosition.Left/Rightnow respects RTL (FlowDirection.RightToLeft) when laying out image+text, preserving configured spacing and preventing overlap/excess separation.CollectionView/CarouselViewbehavioral fixes across platforms (selection/scrolling/layout/empty-state):CollectionViews with no items and noEmptyViewnow collapse to zero in the scroll direction instead of using an expansive fallback desired size; includes a handler safeguard to force a temporary layout pass when nativeUICollectionViewframe is still zero after transitioning from empty to non-empty.EmptyViewis now kept as a subview of the nativeUICollectionView(not inserted above it), fixing a case where pull-to-refresh viaRefreshViewdidn’t work because the empty view intercepted pan gestures; RTL is preserved by applying FlowDirection to the empty-view content while counter-transforming the empty-view host, and transforms are reset before setting frames to avoid UIKit “undefined Frame under transform” issues.CollectionViewiOS) Group/section removal afterINotifyCollectionChanged.Removeis now handled correctly by avoiding a prematureUpdateSectioncall until afterDeleteSectionsreconciles the already-mutated grouped source.CollectionView+GridItemsLayout) Grouped grid spacing/rendering is more consistent: Windows item containers are vertically stretched so the first item in the first group no longer collapses when a group header affects row height; iOS/Mac Catalyst grouped grid sections now apply header/footer boundary spacing andInterSectionSpacingbased on main-axis item spacing so headers don’t visually touch the first row.IsSwipeEnabledandIsBounceEnabledare applied consistently across Android/iOS/Mac Catalyst (including reapplication during layout / when UIKit creates/updates embedded orthogonalUIScrollView); on Android, touch dispatch now honorsIsSwipeEnabledso the carousel can’t still scroll when swipe is disabled.Position,CurrentItem, andIndicatorViewstay in sync across handler detach/reattach: ifPositionchanges while detached, reattachment restores to thatPosition(instead of always restoring based onCurrentItem), while preserving existingCurrentItem-based restore behavior for collection mutation scenarios; teardown cancels iOS scroll debounce work and ignores callbacks whenCurrentItemresolves to an invalid index to prevent post-detach scrolls/position drift (notably observed on iOS 26).ItemsSourcereplacement, a newly setCurrentItemis now honored (avoids stalePositionoverriding intended item on reattach).INotifyCollectionChanged.Replaceis handled as a dedicated path: whenLoop="False"selection is preserved (no reset to first item); whenLoop="True"only visible looped cells are rebound to show the replaced value without full adapter rebuild; includes guards/clamping to avoid teardown-race null issues and invalidScrollToPosition(-1)errors.Picker, resizing, minimize/restore) that previously causedcontentOffsetclamps; restore is armed after non-animated programmatic scrolls and canceled on user drag orItemsSource/layout changes (Y-axiscontentOffsetKVO monitoring), with new Mac Catalyst public override surfaces for lifecycle/interaction handling.HtmlWebViewSourcenavigation (MauiWKWebView.LoadHtml) usesWKWebView.LoadSimulatedRequeston iOS 15+/Mac Catalyst 15+ so HTML pages are added to history andWebView.GoBack()/GoForward()work afterHtmlWebViewSourcenavigation; iOS 13/14 continues to useLoadHtmlString, baseUrl/bundle-path origin behavior remains consistent, and HTML content is not exposed viaWKWebView.Url(only base URL is reflected).WebView.Settings.MinimumFontSizeandMinimumLogicalFontSizeto1, preventing default minimum font sizes (often 8px) from clamping small CSSfont-sizevalues.WebMessagePortdelivered via a'capturePort'window message before callingBlazor.start(), setswindow.__BlazorStartedonly after theBlazor.start()promise resolves, and filters dispatched messages so only nativePostWebMessageevents withevent.source === nullare forwarded.intent://andandroid-app://by creating theIntentviaCreateIntentForExternalUrithat forcesCATEGORY_BROWSABLE, clears explicit component/selector, and masks flags to an allowlist (can change which apps can be launched vsIntent.ParseUri(..., Scheme)).args.Source/message.FrameInfo.Request.Urlis an absolute URI under the handler’sAppOriginUri.https://appdir/virtual host mapping is now treated as local appdir content only when the parsed absolute URI is HTTPS, has no userinfo, and host is exactlyappdir(case-insensitive), and appdir mapping is cleared on navigation to non-appdirhosts; additionally, appdir mapping now usesCoreWebView2HostResourceAccessKind.DenyCors(wasAllow), so cross-originfetch/XHR tohttps://appdir/...is no longer allowed (while normal sub-resources and same-origin fetch from a realhttps://appdir/page loaded viaLoadUrlstill work).SearchHandler.ShowsResultsnow updates the search results UI dynamically at runtime across Android (dropdown/filtering threshold behavior), iOS/Mac Catalyst (recreatesUISearchControllerwhenShowsResultschanges while preserving current query text), and Windows (AutoSuggestBox.ItemsSourcetoggled tonullwhen results disabled and resynchronized when re-enabled, including whenItemsSourcechanges).SearchHandler.FontFamily,FontSize, andFontAttributesare now applied to the nativeAutoSuggestBoxon attach and when changed (previously ignored).TextColoris no longer applied via an internal class style that blocked user styles; default is applied directly to the generatedLabelat the lowest specificity so user-provided styling (implicitStyle TargetType="Label"and explicit/class styles likeClass="FlyoutItemLabelStyle") reliably overrides it, matching iOS/Windows behavior.InputTransparent="True"(or handler hit-test behavior) and non-nullBackgroundno longer lose their visible background color; WindowsLayoutPanelnow renders a non-hit-testable background layer behind children.MauiContextwindow scope is disposed (tracked via internalMauiContext.IsWindowScopeDisposed), preventing shutdown-timeObjectDisposedException(e.g., focus loss triggering mapper work during window close).AppWindowPresenterKind.FullScreen, MAUI suppresses the title-bar height reservation (eliminates ~32px gap and restores pointer/mouse interactivity in the top area), updates dynamically on entering/exiting full-screen while modal is visible, and respects explicitWindow.TitleBar/TitleBar.IsVisible.Borderstroke line-cap mapping now also applies to dashed strokes (Path.StrokeDashCapset alongsideStrokeStartLineCap/StrokeEndLineCap) soStrokeLineCapaffects dashed borders as expected.SwipeView(WinUISwipeControl) directly inside aBorderno longer crashes WinUI;ContentPanel.UpdateClipskips applying a geometric clip toSwipeControl(border stroke still renders, butSwipeViewcontent/corners won’t be clipped to theBordershape in this scenario).Image.BackgroundColor/IImage.Backgroundupdates via data binding no longer crash with a COMException when theImagehas been unloaded and a bound value changes fromnullto a color; background/container creation is deferred until the nativeImageisIsLoaded(applies when re-entering the visual tree).Label.FormattedText/ formatted text behavior updates across platforms:TapGestureRecognizernow aligns hitboxes with rendered text for custom fonts that include an OpenType STAT table; on iOS 16+NSLayoutManager.UsesFontLeadingis disabled to match CoreText line metrics, and span-rect calculation prefers MAUI’s arrangefinalSizeoverUILabel.Bounds(which can be stale/zero during layout).EffectiveFlowDirection, settingNSParagraphStyle.BaseWritingDirection, mirroringTextAlignment.Start/End, and changingIView.FlowDirectionat runtime triggers a rebuild so paragraph direction/alignment don’t go stale.Label.FormattedTextclears WinUITextBlock.TextHighlighterswhen rebuilding inlines so old highlight/background ranges don’t persist onto new formatted text.FormattedTextno longer risks UI-thread hangs and eventualOutOfMemoryExceptionwhen created/updated while hidden (collapsed) and later shown; span-position recalculation now guards against zero/negative measured line heights to avoid an infinite layout loop.ContentPage.HideSoftInputOnTapped(Android/iOS) is now determined only by the currently focused input’s enclosingContentPage(via liveElement.Parentchain with a fallback to cached enclosing page while focus remains), fixing a “sticky” case where a previously navigated/hidden page could keep the behavior effectively enabled for subsequent pages.Entrypassword behavior (iOS/Windows):Keyboard="Password"no longer forces masking whenIsPassword="False"—IsPasswordis now respected on initial load (iOS+Windows) and when toggled at runtime (Windows).Entry)Entry.Completedis no longer raised when the user presses Enter to confirm a Chinese/Japanese IME candidate;Completednow fires only on Enter KeyUp if a matching Enter KeyDown was observed (reset on focus loss).Entry) WithClearButtonVisibilityenabled andTextColorset, the built-in clear button (✕) now tints at full opacity to matchTextColorinstead of rendering dim/faded.Entry)Keyboard="Numeric"and similar non-password input types no longer clear password-variation bits unless actually present, restoring the ability to input the OS-locale decimal separator.Window/Page.OnBackButtonPressed) now detects when a page overridesOnBackButtonPressedand ensures the override always receives the back press instead of relying solely on container/navigation-state heuristics.Backgroundclearing and updates were corrected/expanded:Image/ImageButtonbackground mapping now truly clears rendered background when set to null/empty (removes background layer and resets native background color), including support forImageSourcePaintbackgrounds;Imagealso reappliesIView.Opacityafter background changes to avoid compounded opacity when containers/wrappers transition.DatePickerandTimePickernow correctly clear the native background whenBackgroundis set tonullat runtime (remove background layer and resetBackgroundColor), aligning iOS/Mac behavior with documentedBackgroundbehavior.SwipeView/SwipeItemuser-visible behavior improvements:SwipeView/SwipeItemnow updates swipe-item background on app theme changes (e.g.,AppThemeBindingonSwipeItem.BackgroundColor) by triggering handler background updates and fixing property mapping toISwipeItemMenuItem.Background; on iOS and Windows, background updates also re-applyITextStyle.TextColor.SwipeItem/SwipeItemViewcommands can now be activated via TalkBack (ACTION_CLICK/ double-tap to activate);SwipeBehaviorOnInvoked(e.g., auto-close vsRemainOpen) is still honored.Exactlyfor default items (to keep text visible), but height is now always measured withAtMostso buttons can self-size and keep icon+text vertically centered (may change sizing vs prior releases).FlexLayoutfixes: measurement was adjusted so children aren’t measured against full container size when margins/fixed cross-axis sizing mean the view will be arranged narrower (fixes word-wrap cases where last line could be clipped), and on Windows post-detach layout/measure calls are safely ignored (avoids NRE crashes in virtualized templates) with detached measure/frame queries returning zero sizes/rects.x:Codeis not an immediate child of the root element; MAUIX2016 whenx:Codeis used withoutx:Classon the root element.{Margin.Top}via copy–modify–writeback; when a struct intermediate property has no public setter and the binding is TwoWay (or TwoWay-by-default), the generator omits the setter (binding becomes effectively one-way) and emits theStructIntermediateNotSettablewarning, whose diagnostic ID changed from MAUIX2017 to MAUIX2018.xmlnsprefixes inside{...}expressions and attached bindable property reads via target-qualifiedtarget.(Type.Property)/this.(Type.Property)rewritten toType.GetProperty(target); the standalone{(Type.Property)}form is explicitly rejected with a diagnostic instructing authors to usethis.(...)orelement.(...)(no two-way setters or ABP change-notification support is generated).BindingSourceGen-{stableHash}-{line}-{column}.g.cs) instead of embedding full source file paths, changing emitted generated filenames whenEmitCompilerGeneratedFilesis enabled and preventing WindowsMAX_PATHfailures.MauiFontandMauiSplashScreenassets are reliably included on first build and after deletingobj: font collection is moved to always-run_CollectMauiFontItems, and incremental tracking switches from stamp files to output manifests (mauifont.outputs,mauisplash.outputs) so missing outputs re-trigger only affected targets; iOS/Mac Catalyst font registration de-duplicates colliding font filenames and deletes staleMauiInfo.plistwhen the lastMauiFontis removed.dotnet new mauimobile template with--sample-content: generatedMainPageModel.InitData()no longer callsRefresh(), so initial startup loads once (initial refresh remains triggered fromAppearing()), avoiding duplicate refresh/data loading.dotnet newapp templates for iOS and Mac Catalyst now default to UIKit’s scene-based lifecycle by adding aUIApplicationSceneManifest+ aSceneDelegatederiving fromMicrosoft.Maui.MauiUISceneDelegate(withUIApplicationSupportsMultipleScenes=falseand required configuration name__MAUI_DEFAULT_SCENE_CONFIGURATION__), and these templates raise the default Mac CatalystSupportedOSPlatformVersionto 17.0 (macOS 14).iOSLifecycle.PerformActionForShortcutItem) must now invokecompletionHandlerexactly once; MAUI aggregates multiple handlers and completes the native callback after handlers return and either one reportstrueor all reportfalse. New public override point:MauiUISceneDelegate.PerformAction(UIWindowScene, UIApplicationShortcutItem, Action<bool>). Essentials AppActions on iOS reportshandled=falseon exceptions before rethrowing and only returnshandled=truewhenAppActionActivatedhas subscribers.MauiAppBuilder.ConfigureEssentialson iOS forwards scene-based authentication callbacks (SceneOpenUrlandSceneContinueUserActivityforWebPageUrl) toWebAuthenticator.Defaultfor scene-based lifecycle apps (forwarding is limited to WebAuthenticator handling and does not replay cold-connection URLs/activities only available viaSceneWillConnect).dotnet new maui-mobiletemplate (Android/TalkBack): TaskDetailPage/ProjectDetailPage now apply accessibility text to the interactivePickercontrols usingSemanticProperties.Hint(instead of settingSemanticProperties.Descriptionon a non-interactive wrapper), fixing TalkBack navigation so users can reach/activate the pickers and continue to subsequent controls.maui-mobiletemplate: ComboBoxSemanticProperties.Hinttext updated to include an initial “State Collapsed” hint to improve macOS VoiceOver announcement of initial collapsed/expanded state.Permissions.RequestAsync<T>()on Android validatesMainThread.IsMainThreadbefore registering request code (and cleans up ifActivityCompat.RequestPermissionsthrows), so repeated background-thread calls still throwPermissionExceptionbut won’t poison later valid main-thread prompts with “same key has already been added”.Screenshot.Default.CaptureAsync()on Android avoids deadlocks when callers synchronously block on the UI thread by dispatching the PixelCopy completion callback on a dedicatedHandlerThreadand usingConfigureAwait(false); if PixelCopy fails off the main thread, capture now returns failure (null) instead of attempting view-based fallbacks off the UI thread.sysctlbynameP/Invoke signature to usesize_t-sized parameters (nuintandref nuint), reducing unexpectedInvalidOperationExceptionfailures when reading system properties.MediaPickeron Android (Photo Picker path) now requires the currentActivityto be anAndroidX.Activity.ComponentActivityand requires callingMicrosoft.Maui.ApplicationModel.Platform.Init(Activity, Bundle)inOnCreate; otherwise throwsInvalidOperationExceptionwith explicit guidance. The Android activity-result infrastructure was redesigned so activity-result launchers and pending requests are tracked per-ComponentActivityinstance (with instance-state persistence and lifecycle cleanup), enabling multiple activities to useMediaPickerindependently and avoiding clobbered/hung requests across recreation/concurrent launches.MediaPickeron iOS no longer throwsUIKitThreadAccessExceptionwhen picking multiple items (2+), by capturing eachPHPickerResult.ItemProvideron the main thread before anyawait.Accelerometer.ReadingChangedandShakeDetectedwere changed to a weak-subscription model and then reverted back to standard .NET event semantics; the final behavior is standard C# events (handlers are held strongly, and apps should unsubscribe with-=to avoid retaining subscribers).SemanticProperties.Descriptionis now always mapped to the native Android accessibility node’sContentDescriptionfor all views includingEntry/EditText(previouslyEntryonly injected description into nodeText); synthesized editable control text behavior is preserved (e.g.,ContentDescription= description,Text= “description, entry text”).Pickerplatform views restore horizontal drag scrolling for long selected values by delegating touch events toScrollingMovementMethodwhile keepingDefaultMovementMethodnull (read-only, no cursor/text selection), cancel click/press when a drag exceeds touch slop, and disable long-click (LongClickable = false)..github/skills/release-readiness: addsNew-ReleaseHandoff.ps1+references/release-handoff.mdto generate deterministic public-safe Preview/SR handoff outputs (validates/omits non-public URLs and sensitive data; requires explicitPublicEvidence: truein evidence JSON), updatesPreviewInstallability.ps1to generate isolated NuGet config withpackageSourceMappingand a prior-major compatibility feed for .NET majors > 8, updates the skill docs to reflect the new workflows, andGet-PreviewReadiness.ps1adds optional local net11 internal “official build health” enrichment that is emitted only when-PublicSafe:$falseand always skipped on GitHub Actions.Suggestions
Instructions for Copilot: Copilot should only fix suggestions with a checkmark and do not make any updates for unchecked suggestions.
Note
Suggestions are generated by AI and they should be reviewed by human before assigning it to Copilot. Please uncheck the ones you don't want Copilot to work on. Then assign this issue to Agent (GitHub Copilot).
📚 To learn more about agentic content maintenance workflow, visit Agentic workflow for Learn content maintenance. Sign in using Learn Profile to access the content on this link.
💬 Share your feedback on the Learn Content Maintenance Agentic Workflow here.