Skip to content

[net11.0] Trimmable element handlers#29952

Open
simonrozsival wants to merge 2 commits intonet11.0from
dev/simonrozsival/net10.0-use-element-handler-attributes
Open

[net11.0] Trimmable element handlers#29952
simonrozsival wants to merge 2 commits intonet11.0from
dev/simonrozsival/net10.0-use-element-handler-attributes

Conversation

@simonrozsival
Copy link
Member

@simonrozsival simonrozsival commented Jun 12, 2025

This is a follow-up to #28357

Summary

All built-in controls now use [ElementHandler] attributes instead of DI registration for handler resolution. This removes the need for AppHostBuilderExtensions.AddControlsHandlers() and makes handler associations visible at the type level, improving trimmability.

Key changes

[ElementHandler] attribute

  • New public ElementHandlerAttribute on view types (e.g., [ElementHandler(typeof(ButtonHandler))]) declaratively associates a view with its handler
  • Inherited = false — each concrete type that needs a different handler must declare its own attribute
  • The attribute walks the BaseType chain at resolution time, so derived types without their own attribute inherit the nearest ancestor's handler

Handler resolution in MauiHandlersFactory

Both GetHandler(Type) and GetHandlerType(Type) follow the same 4-step resolution order:

  1. Exact DI registration — if the concrete type (e.g., typeof(Button)) is registered via AddHandler<Button, MyButtonHandler>(), that wins. DI-registered handlers are instantiated through MauiFactory.GetService().
  2. [ElementHandler] attribute — walk the type's BaseType chain looking for the attribute. Attribute-based handlers are instantiated via Activator.CreateInstance().
  3. Interface-based DI registration — map the concrete type to its virtual view interface (e.g., ButtonIButton) using RegisteredHandlerServiceTypeSet, then look up the interface in DI. This is the path for third-party/custom handler overrides registered via AddHandler<IButton, ...>().
  4. IContentView fallback — if the type implements IContentView, return ContentViewHandler.

GetHandler() is the primary API — it returns an instantiated IElementHandler. GetHandlerType() returns only the Type and is used by code that needs to compare handler types without instantiating them (e.g., Compatibility layer cell renderers).

ElementExtensions.ToHandler() / SetHandler()

These methods call GetHandler() directly. When a handler requires constructor parameters (no parameterless constructor), ToHandler() catches the MissingMethodException and falls back to ActivatorUtilities.CreateInstance() with DI injection. This fallback path is cached per-type in a HashSet<Type> to avoid repeated exception throwing.

Mapper remapping via static constructors

  • Controls-layer types override Core-layer mapper entries in their static constructors
  • Base-class static constructor ordering is enforced via RemappingHelper.EnsureBaseTypeRemapped(), which accesses a s_forceStaticConstructor field on the parent type to force the runtime to run the parent's static constructor first
  • RemappingDebugHelper.AssertBaseClassForRemapping (DEBUG-only) validates that no intermediate type in the hierarchy is accidentally skipped

Cleanup

  • Removed IElementHandlerWithAndroidContext interface and ElementHandlerWithAndroidContextAttribute
  • Removed dead RemapForControls(this MauiAppBuilder) extension method and old RemapForControls()/RemapIfNeeded() pattern
  • Fixed Slider not having a static constructor (was only called explicitly from the removed extension method)
  • Restored IMauiHandlersFactory.GetHandler() to its original signature (GetHandler(Type) / GetHandler<T>()) — no longer requires IMauiContext parameter
  • Removed unused MauiContext/HandlersContextStub declarations from tests and benchmarks

Copilot AI review requested due to automatic review settings June 12, 2025 07:43
@simonrozsival simonrozsival requested a review from a team as a code owner June 12, 2025 07:43
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR transitions built-in controls from DI registration to using [ElementHandler] attributes, introduces IElementHandlerWithAndroidContext<T> for Android renderers, and adds a new MSBuild property to toggle CSS support.

  • Apply [ElementHandler] to core controls and cells instead of DI
  • Introduce IElementHandlerWithAndroidContext<T> and CreateHandler(Context) on Android renderers
  • Add MauiCssEnabled MSBuild property and corresponding runtime host configuration

Reviewed Changes

Copilot reviewed 120 out of 120 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Controls/src/Core/ContentPage/ContentPage.Mapper.cs Added static ctor calling RemapForControls and VisualElement.RemapIfNeeded
src/Controls/src/Core/Compatibility/Handlers/TableView/Android/TableViewRenderer.cs Implemented IElementHandlerWithAndroidContext<TableViewRenderer> and CreateHandler
src/Controls/src/Core/Compatibility/Handlers/ListView/Android/ListViewRenderer.cs Implemented IElementHandlerWithAndroidContext<ListViewRenderer> and CreateHandler
src/Controls/src/Core/Compatibility/Handlers/Android/FrameRenderer.cs Implemented IElementHandlerWithAndroidContext<FrameRenderer> and CreateHandler
src/Controls/src/Core/Cells/*.cs Added [ElementHandler<...>] attributes for compatibility cell renderers
src/Controls/src/Core/Button/Button.cs Added [ElementHandler<ButtonHandler>]
src/Controls/src/Core//.Mapper.cs Added static ctors calling RemapForControls / RemapIfNeeded
src/Controls/src/Build.Tasks/nuget/.../Microsoft.Maui.Controls.targets Added MauiCssEnabled property and runtime host configuration option
src/Compatibility/Core/src/{iOS,Android}/Platform.cs Updated GetHandler calls to pass MauiContext
Comments suppressed due to low confidence (1)

src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.targets:240

  • Added the MauiCssEnabled build property but no corresponding public documentation under /docs/; please update the XML docs to describe this new feature.
<MauiCssEnabled Condition="'$(MauiCssEnabled)' == '' and '@(MauiCss->Count())' == '0'">false</MauiCssEnabled>

{
#pragma warning disable CS0618 // Type or member is obsolete
public class TableViewRenderer : ViewRenderer<TableView, AListView>
public class TableViewRenderer : ViewRenderer<TableView, AListView>, IElementHandlerWithAndroidContext<TableViewRenderer>
Copy link

Copilot AI Jun 12, 2025

Choose a reason for hiding this comment

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

Implementing IElementHandlerWithAndroidContext introduces a new public interface on this renderer, which is a breaking API change; please assess version impact.

Copilot uses AI. Check for mistakes.
{
#pragma warning disable CS0618 // Type or member is obsolete
public class ListViewRenderer : ViewRenderer<ListView, AListView>
public class ListViewRenderer : ViewRenderer<ListView, AListView>, IElementHandlerWithAndroidContext<ListViewRenderer>
Copy link

Copilot AI Jun 12, 2025

Choose a reason for hiding this comment

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

Implementing IElementHandlerWithAndroidContext introduces a new public interface on this renderer, which is a breaking API change; please assess version impact.

Copilot uses AI. Check for mistakes.
{
[Obsolete("Frame is obsolete as of .NET 9. Please use Border instead.")]
public class FrameRenderer : CardView, IPlatformViewHandler
public class FrameRenderer : CardView, IPlatformViewHandler, IElementHandlerWithAndroidContext<FrameRenderer>
Copy link

Copilot AI Jun 12, 2025

Choose a reason for hiding this comment

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

Implementing IElementHandlerWithAndroidContext introduces a new public interface on this renderer, which is a breaking API change; please assess version impact.

Copilot uses AI. Check for mistakes.
@simonrozsival simonrozsival marked this pull request as draft June 12, 2025 08:06
@mattleibow
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@PureWeen PureWeen added this to the .NET 10.0-preview6 milestone Jun 17, 2025
@PureWeen PureWeen moved this from Todo to In Progress in MAUI SDK Ongoing Jun 17, 2025
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/net10.0-use-element-handler-attributes branch from 33afe18 to c49e57e Compare June 18, 2025 11:53
@PureWeen PureWeen added platform/macos macOS / Mac Catalyst platform/windows platform/android platform/ios area-architecture Issues with code structure, SDK structure, implementation details labels Aug 7, 2025
@simonrozsival
Copy link
Member Author

@copilot there are merge conflicts in this branch. please resolve them. When you're done, write summary of what this PR does and what functionality is missing to fully convert the "old" way of implementing handlers to the "new" way.

Copy link
Contributor

Copilot AI commented Nov 25, 2025

@simonrozsival I've opened a new pull request, #32861, to work on those changes. Once the pull request is ready, I'll request review from you.

@simonrozsival
Copy link
Member Author

@copilot oops, try now!

Copy link
Contributor

Copilot AI commented Nov 25, 2025

@simonrozsival I've opened a new pull request, #32862, to work on those changes. Once the pull request is ready, I'll request review from you.

@simonrozsival
Copy link
Member Author

@copilot there are several errors popping up:

  • src\Controls\src\Core\Shell\Shell.cs(29,25): Error CS0246: The type or namespace name 'ShellHandler' could not be found (are you missing a using directive or an assembly reference?)
  • src\Controls\src\Core\Shell\ShellItem.cs(18,25): Error CS0246: The type or namespace name 'ShellItemHandler' could not be found (are you missing a using directive or an assembly reference?)
  • buildtasks/Microsoft.Maui.Controls.Build.Tasks.After.targets(15,3): error MSB4024: The imported project file "/mnt/vss/_work/1/s/.buildtasks/Microsoft.Maui.Controls.targets" could not be loaded. Name cannot begin with the '<' character, hexadecimal value 0x3C. Line 325, position 2. [/mnt/vss/_work/1/s/src/BlazorWebView/tests/DeviceTests/MauiBlazorWebView.DeviceTests.csproj]

Fix them and make sure the product can be built.

Copy link
Contributor

Copilot AI commented Dec 1, 2025

@simonrozsival I've opened a new pull request, #32933, to work on those changes. Once the pull request is ready, I'll request review from you.

@simonrozsival simonrozsival force-pushed the dev/simonrozsival/net10.0-use-element-handler-attributes branch 5 times, most recently from 1386e4a to 81acaeb Compare January 19, 2026 08:52
@simonrozsival simonrozsival marked this pull request as ready for review January 19, 2026 10:14
@simonrozsival simonrozsival changed the title [net11.0] Use ElementHandlerAttribute instead of DI for built-in visual elements [net11.0] Trimmabler element handlers Jan 20, 2026
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/net10.0-use-element-handler-attributes branch from dbd26ce to 4dbc042 Compare January 20, 2026 13:37
@simonrozsival simonrozsival changed the title [net11.0] Trimmabler element handlers [net11.0] Trimmable element handlers Jan 26, 2026
@rmarinho
Copy link
Member

/rebase

@simonrozsival
Copy link
Member Author

@copilot this PR needs a proper rebase with conflict resolution. open a PR which addresses this issue. make sure it is up to date with the base net11.0 branch.

Copy link
Contributor

Copilot AI commented Feb 12, 2026

@simonrozsival I've opened a new pull request, #34008, to work on those changes. Once the pull request is ready, I'll request review from you.

@simonrozsival simonrozsival force-pushed the dev/simonrozsival/net10.0-use-element-handler-attributes branch from 4dbc042 to b8a94ba Compare February 13, 2026 08:37
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/net10.0-use-element-handler-attributes branch 3 times, most recently from c1ce0c9 to 13753db Compare February 18, 2026 14:15
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/net10.0-use-element-handler-attributes branch from f5c8447 to f097792 Compare February 19, 2026 14:21
@albyrock87
Copy link
Contributor

albyrock87 commented Feb 20, 2026

It's not clear to me @simonrozsival how one can create their own Button handler.
Would they still use the DI?
If not, how can the system know which one to use? (The MAUI one or the custom one)

Edit: yes it seems DI win, thanks!

So this is basically a feature for library authors to make their handlers trimmable.

@simonrozsival
Copy link
Member Author

@albyrock87 exactly. If you don't use webview in your app, there should be no webview related code in the app.

This change should be as transparent as possible. Any custom handler registered via DI should still work.

@StephaneDelcroix StephaneDelcroix force-pushed the dev/simonrozsival/net10.0-use-element-handler-attributes branch from f097792 to 6695f72 Compare February 27, 2026 15:28
@github-actions
Copy link
Contributor

github-actions bot commented Feb 27, 2026

🚀 Dogfood this PR with:

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

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

Or

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

Squashed for clean rebase onto net11.0.
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/net10.0-use-element-handler-attributes branch from 6695f72 to d3fb530 Compare March 11, 2026 09:52
Handlers resolved via [ElementHandler] attribute use
Activator.CreateInstance(), not ActivatorUtilities.

Co-authored-by: Copilot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-architecture Issues with code structure, SDK structure, implementation details copilot platform/android platform/ios platform/macos macOS / Mac Catalyst platform/windows

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

7 participants