Build Reactor's DataTemplates from code instead of parsing markup - #1125
Draft
Alexandre Zollinger Chohfi (azchohfi) wants to merge 2 commits into
Draft
Build Reactor's DataTemplates from code instead of parsing markup#1125Alexandre Zollinger Chohfi (azchohfi) wants to merge 2 commits into
Alexandre Zollinger Chohfi (azchohfi) wants to merge 2 commits into
Conversation
Contributor
🧪 Merged coverageCaution Coverage run failed for |
Contributor
📦 Build metricsCaution The build-metrics run did not produce artifact sizes (build failed). See the workflow run. |
Reactor builds two DataTemplates at runtime by handing XamlReader.Load a
markup string: the ContentControl shell every items control mounts
(ListView/GridView/FlipView), and the legacy text-node TreeView template.
Both exist only because DataTemplate could not be constructed from code.
microsoft-ui-xaml adds `new DataTemplate(DataTemplateElementFactory)`, which
takes a callback returning the subtree. This ports both templates onto it.
Beyond removing a runtime XAML parse, the TreeView template loses its
`{Binding Content.Content}`. A classic Binding resolves that path by string
through CsWinRT's ICustomPropertyProvider — reflection, which NativeAOT trims
unless the source type is annotated (that annotation is what #1108 added), and
which costs a reflective lookup per realized row even when it works. Reading
the same chain in a DataContextChanged handler is strongly typed: no
annotation needed, no lookup, and the event re-fires on recycling so reused
rows retext correctly.
The `[WinRT.GeneratedBindableCustomProperty]` attribute on TreeViewNodeData is
deliberately left in place. Reactor no longer needs it, but it is public API
surface that consumers binding to TreeViewNodeData themselves still rely on.
DO NOT MERGE YET. The constructor is gated behind
`[feature(Feature_ExperimentalApi)]` in microsoft-ui-xaml and has not shipped
in a public Windows App SDK, so CI cannot restore this branch: the versions in
Directory.Build.props are an internal experimental build and do not resolve
from public feeds. When the API ships, update those two versions and drop the
metapackage opt-out in the selftest host; no other change should be needed.
Validated against Microsoft.WindowsAppSDK.WinUI 3.0.0-experimental.260818.21
(the PR-built native core, Microsoft.ui.xaml.dll 3.3.0.2608): full selftest
suite 1447 planned / 0 failures, with the text-node TreeView fixture green on
both the mount and update arms.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 17bce8bb-d57a-4f76-a55d-27c9029fc9a3
#1108 annotated TreeViewNodeData with [WinRT.GeneratedBindableCustomProperty] for exactly one reason: Reactor's own text-node TreeView template bound "Content.Content", and that string path is resolved by reflection, which NativeAOT trims. This branch replaces that binding with a DataContextChanged handler, so the reason is gone -- there is now no {Binding} anywhere in src/ and no SetBinding call site. The attribute never shipped: v0.1.0-preview.13 and every earlier tag predate #1108, so no released build has it, and binding to TreeViewNodeData from a consumer-supplied template was already broken under NativeAOT in all of them. Removing it therefore takes nothing away that ever worked in a release; it declines to keep a side effect of an internal fix. Keeping it would carry a workaround, plus `partial` on a public record, for a scenario Reactor does not use and does not document. The limitation is now written down instead: docs/aot-support.md gains a row explaining that a classic {Binding} in a hand-supplied DataTemplate is not trim-safe, that Reactor's own templates avoid it by populating content in a DataContextChanged handler, and that a consumer installing their own template via an escape hatch should do the same or annotate their own type. Also disambiguates the IElementFactory cref in IItemsRepeaterFactorySource. The Windows App SDK this branch targets adds Microsoft.UI.Xaml.IElementFactory alongside the existing Microsoft.UI.Xaml.Controls.IElementFactory, so the bare cref became ambiguous (CS0419) and failed the warnings-as-errors Release build. Points at the Controls one, which is what the member returns. Validated: src/Reactor Release build 0 warnings / 0 errors; selftest suite 1447 planned with only the known WindowLevel_RuntimeFlip_Topmost Z-order flake failing under full-suite load (passes 3/3 in isolation, unrelated to these files). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17bce8bb-d57a-4f76-a55d-27c9029fc9a3
Alexandre Zollinger Chohfi (azchohfi)
force-pushed
the
azchohfi-winui3-integration-datatemplate
branch
from
August 25, 2026 22:30
9cfd5c5 to
7b0195f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Important
Draft — do not merge yet. This is blocked on a public Windows App SDK release that ships the code-based
DataTemplateconstructor. CI on this branch cannot pass: the versions inDirectory.Build.propspoint at an internal experimental build that does not resolve from public feeds. Parked here so the change is ready to go the day the API ships.What this does
Reactor builds two
DataTemplates at runtime by handingXamlReader.Loada markup string:SharedContentControlTemplate— theContentControlshell every items control mounts (ListView / GridView / FlipView)TreeViewTextItemTemplate— the legacy text-node TreeView item templateBoth exist only because
DataTemplatecould not be constructed from code. microsoft-ui-xaml addsnew DataTemplate(DataTemplateElementFactory), which takes a callback returning the subtree, so this ports both onto it and Reactor stops parsing XAML at runtime for item templates.The part that is more than cosmetic
The TreeView template also loses its
{Binding Content.Content}.A classic
{Binding}resolves that path by string, through CsWinRT'sICustomPropertyProvider— i.e. reflection. That means it is trimmed away under NativeAOT unless the source type carries generated binding metadata, and even where it works it costs a reflective lookup per realized row.Reading the same chain in a
DataContextChangedhandler is strongly typed:No metadata required, no reflective lookup, and the event re-fires when a virtualized row is recycled onto new data, so reused rows retext correctly.
x:Bindis not an alternative here — it is a XAML-compiler feature that generates code, so it is unavailable from a code-built subtree.DataContextChangedis the AOT-safe route, which matches the guidance in the upstream API discussion.Removing the binding metadata attribute
#1108 annotated
TreeViewNodeDatawith[WinRT.GeneratedBindableCustomProperty]for exactly one reason: to keep the{Binding Content.Content}above working under NativeAOT. This branch deletes that binding, so the attribute — and thepartialit forced onto a public record — goes with it. After this change there is no{Binding}anywhere insrc/and noSetBindingcall site.It never shipped:
v0.1.0-preview.13and every earlier tag predate #1108, so no released build carries it, and binding toTreeViewNodeDatafrom a consumer-supplied template was already broken under NativeAOT in all of them. Removing it takes away nothing that ever worked in a release.The limitation is written down instead of silently dropped —
docs/aot-support.mdgains a row explaining that a classic{Binding}in a hand-suppliedDataTemplateis not trim-safe, that Reactor's own templates avoid it by populating content in aDataContextChangedhandler, and that a consumer installing their own template through an escape hatch such asTreeView(...).Set(tv => tv.ItemTemplate = ...)should do the same or annotate their own type.Incidental: an ambiguous cref
The Windows App SDK this branch targets adds
Microsoft.UI.Xaml.IElementFactoryalongside the existingMicrosoft.UI.Xaml.Controls.IElementFactory, which makes the bare<see cref="IElementFactory"/>inIItemsRepeaterFactorySourceambiguous —CS0419, an error under warnings-as-errors in Release. Disambiguated to theControlsone, which is what the member returns.Validation
Validated against
Microsoft.WindowsAppSDK.WinUI 3.0.0-experimental.260818.21(the PR-built native core,Microsoft.ui.xaml.dll3.3.0.2608):src/ReactorRelease build: 0 warnings, 0 errorsWindowLevel_RuntimeFlip_TopmostZ-order flake failing under full-suite load (passes 3/3 in isolation, unrelated to these files)TXB_(text-node TreeView),TTV_(templated TreeView) andKLR_(keyed ListView/GridView/ItemsRepeater) all green — mount, update and recycling armsDataContextpropagation and element recycling behave identically to JITUnblocking checklist
When the API ships in a public Windows App SDK:
WindowsAppSDKVersion/WindowsAppSDKWinUIVersioninDirectory.Build.propsto the released versions and delete the placeholder commentReactorSkipWinAppSDKInjectionand the explicit split-package references intests/Reactor.AppTests.Host/Reactor.AppTests.Host.csproj(they exist only because the experimental aggregate caps WinUI below 3.0.0 and cannot resolve alongside the WinUI slice)No other change should be required.
Related
microsoft-ui-xamlonmain:DataTemplate_Partial.h, with the public surface inmicrosoft.ui.xaml.controls.controls.idl— currently[feature(Feature_ExperimentalApi)],[contract(WinUIContract, 12)]docs/specs/proposals/winui3-integration.md("Programmatic DataTemplate Construction Without XamlReader"). The themingXamlReader.LoadforStyle(§22/§23) is a separate gap and is untouched.{Binding}path alive on today's SDK.