-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[Proposal] [XSG] Reduce compiled binding friction #34696
Description
Problem
Compiled bindings require too much manual ceremony and produce confusing diagnostics. As AOT/trimming become the default, these friction points block adoption:
- Manual type annotations everywhere.
x:DataTypemust be set on every DataTemplate and overridden on every cross-scope binding — even when the compiler has enough information to infer the type. - False warnings on working code. MAUIG2045 fires for
x:Referenceand Behavior bindings that work at runtime. WithTreatWarningsAsErrors, this breaks builds. - Cross-scope bindings aren't compiled. Binding to the page ViewModel from inside a DataTemplate requires verbose
RelativeSourceorx:Referencemarkup — and the result still uses reflection, which gets trimmed under AOT.
Before / After
Binding to the page ViewModel from inside a CollectionView.ItemTemplate:
Today: verbose, not compiled, false warnings
<ContentPage x:Name="PageRoot"
x:Class="local:ProductsPage"
x:DataType="vm:ProductsViewModel"> <!-- tells the compiler the BindingContext type -->
<CollectionView ItemsSource="{Binding Products}">
<CollectionView.ItemTemplate>
<!-- must manually match ObservableCollection<Product> -->
<DataTemplate x:DataType="models:Product">
<Grid>
<Label Text="{Binding Name}" />
<!-- ⚠ x:DataType override needed to suppress false MAUIG2045 -->
<!-- ❌ not compiled — falls back to reflection, trimmed under AOT -->
<Button Command="{Binding BindingContext.SelectCommand, Source={x:Reference PageRoot}, x:DataType=local:ContentPage}"
CommandParameter="{Binding .}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>Goal: same intent, compiled, no warnings
<ContentPage x:Name="PageRoot"
x:Class="local:ProductsPage"
x:DataType="vm:ProductsViewModel"> <!-- tells the compiler the BindingContext type -->
<CollectionView ItemsSource="{Binding Products}">
<CollectionView.ItemTemplate>
<!-- ✅ x:DataType inferred from ProductsViewModel.Products : ObservableCollection<Product> -->
<DataTemplate>
<Grid>
<Label Text="{Binding Name}" />
<!-- ✅ compiled — PageRoot resolves to ProductsPage, x:DataType gives the BindingContext cast -->
<Button Command="{Binding BindingContext.SelectCommand, Source={x:Reference PageRoot}}"
CommandParameter="{Binding .}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>No new syntax. The compiler uses type information already present in the XAML.
Proposed improvements
New sub-issues
-
Compile
x:Referencebindings — two inference steps:- Element type:
{x:Reference PageRoot}→ resolve the XAML element and its type:ContentPagewithx:Class→local:ProductsPage. Properties likeTitlecompile directly. - BindingContext cast: when the path starts with
BindingContext.Y, use the referenced element'sx:DataTypeto infer the cast →((ProductsViewModel)source.BindingContext).Y.
Related: [net11.0] Compile x:Reference bindings against resolved element type #34513.
- Element type:
-
Support named element access in C# expressions —
{PageRoot.BindingContext.Cmd}resolves named elements as page fields. Opt-in, experimental. -
Improve warning quality — suppress false MAUIG2045 for non-context sources, include types in diagnostics, suppress XC0022 for
Source={x:Null}/{x:Static}.
Tracked in existing issues
- Infer DataTemplate
x:DataTypefrom collection generic type — [Feature] Auto compiled binding on CollectionView's ItemTemplate, GroupHeaderTemplate and GroupFooterTemplate #8161 - Compile
RelativeSource AncestorType— [XSG] Optimize compiled bindings for RelativeSource with explicit Source #33249 / PR Fix for RelativeSource AncestorType bindings not generating compiled bindings under AOT #34408 - Compile
RelativeSource Self— element type is always known at compile time; trivial case. - Fix Behavior binding story — Enable the inheritance of the parent's BindingContext for Behaviors, based on a Flag #26705, RelativeSource Binding Does Not Work For PlatformBehaviors (MCT Touch Behavior) #24313
- Update documentation and examples — reflect new inference capabilities in
dotnet/docs-maui.
Risks
These improvements share a common pattern: bindings that were previously reflection-based become compiled. This is generally positive (better perf, AOT-safe), but has consequences:
| Risk | Impact | Mitigation |
|---|---|---|
| New warnings on existing code. Reflection silently resolves bad paths; compiled bindings report MAUIG2045. | Builds with TreatWarningsAsErrors could break. |
These are pre-existing bugs being surfaced. Warnings are suppressible. |
Inferred vs explicit x:DataType conflict. E.g., DataTemplate x:DataType="Animal" but collection is ObservableCollection<Dog>. |
Could confuse developers or cause silent misresolution. | Explicit x:DataType always wins. Emit info diagnostic on mismatch. |
Runtime type differs from compile-time type. Shadowed (new) members or subclass overrides may resolve differently when compiled. |
Rare, but behavior could change. | Compiled bindings already have this characteristic; inference doesn't make it worse. |
Source generator ordering. Inferred types may depend on other generators (e.g., CommunityToolkit.Mvvm [RelayCommand]). |
Path resolution could fail if generated members aren't visible yet. | Fall back to runtime binding when type can't be resolved. |
Related PRs
| PR | Status | Description |
|---|---|---|
| #34513 | Open (.NET 11) | Compile x:Reference bindings |
| #34408 | Open (.NET 10 SR6) | Compile RelativeSource AncestorType |
| #34447 | Merged (.NET 10 SR6) | Fix explicit-source bindings in DataTemplates |
| #34501 | Merged (.NET 10 SR5.1) | Fix false MAUIG2045 for x:Reference in DataTemplate |
| #33693 | Merged (.NET 10 SR4) | XAML C# Expressions (experimental) |