Fix XAML C# expression setter generation for read-only properties#34137
Fix XAML C# expression setter generation for read-only properties#34137StephaneDelcroix merged 3 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a comprehensive AI implementation to .NET MAUI, including a new Essentials.AI library that provides on-device AI capabilities using platform-native APIs (Apple Intelligence on iOS/macOS) and cloud-based AI functionality through Azure OpenAI integration. It also includes a full-featured sample app demonstrating AI-powered travel itinerary generation using multi-agent workflows.
Changes:
- Introduces
Essentials.AIlibrary with Apple Intelligence support (iOS 18.5+, macOS 15.2+) for chat and embeddings - Adds comprehensive sample app showcasing AI-driven travel planning with 4-agent workflow
- Updates CI/CD pipelines to support Material3 testing, improve simulator provisioning, and enable Windows unpackaged tests
- Adds device test infrastructure for AI capabilities
- Updates version dependencies (XHarness, Microsoft.Extensions.AI, Microsoft Agent Framework)
Reviewed changes
Copilot reviewed 209 out of 536 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/AI/src/Essentials.AI/Essentials.AI.csproj |
New project file for AI library with platform-specific bindings |
src/AI/src/Essentials.AI/Platform/MaciOS/NLEmbeddingExtensions.cs |
Extension methods to wrap Apple NLEmbedding as IEmbeddingGenerator |
src/AI/src/AppleNative/EssentialsAI/*.swift |
Swift implementation of Apple Intelligence chat client with tool calling support |
src/AI/samples/Essentials.AI.Sample/AI/*.cs |
Multi-agent workflow executors for travel planning (TravelPlanner, Researcher, ItineraryPlanner, Translator) |
src/AI/samples/Essentials.AI.Sample/MauiProgram.cs |
Sample app service registration with OpenAI configuration |
src/AI/tests/Essentials.AI.DeviceTests/*.cs |
Base test classes for ChatClient instantiation, GetService, and cancellation |
eng/pipelines/common/ui-tests.yml |
Adds Material3 build/test stages with API 36 and Pixel 3 XL device profile |
eng/pipelines/common/ui-tests-build-sample.yml |
Adds Material3 build parameter and artifact handling |
eng/pipelines/common/ui-tests-steps.yml |
Adds device skin parameter for Android emulator hardware profiles |
eng/pipelines/common/provision.yml |
Fixes iOS simulator provisioning with better error handling and verification |
eng/helix_xharness.proj |
Re-enables Windows unpackaged tests (previously disabled due to bootstrap failure) |
eng/devices/windows.cake |
Fixes unpackaged build by using _MauiDeviceTestUnpackaged property instead of command-line parameter |
eng/devices/run-windows-devicetests.cmd |
Improves error diagnostics for Windows App SDK bootstrap failures |
eng/Versions.props |
Updates XHarness, adds Microsoft.Extensions.AI and Microsoft Agent Framework dependencies |
.github/workflows/agentics-maintenance.yml |
New auto-generated maintenance workflow for closing expired agentic workflow entities |
.github/skills/try-fix/SKILL.md |
Updates git reset command from git checkout -- . to git checkout HEAD -- . |
.github/skills/ai-summary-comment/*.ps1 |
Removes Tests phase (Phase 2) from PR review workflow, now 4 phases instead of 5 |
.github/agents/pr/*.md |
Updates PR agent to 4-phase workflow (removes Tests phase) |
.github/scripts/shared/Build-AndDeploy.ps1 |
Adds iOS simulator architecture detection for arm64/x64 host machines |
Files not reviewed (1)
- src/AI/src/AppleNative/EssentialsAI/EssentialsAI.xcodeproj/project.xcworkspace/contents.xcworkspacedata: Language not supported
The source generator was generating setter assignments (e.g.,
__source.ReadOnlyText = __value) for getter-only properties when
using C# expression bindings like {ReadOnlyText}. This caused
CS0200 build errors.
The ExpressionAnalyzer.IsSimplePropertyChain() only checks syntax,
not whether the property actually has a public setter. Added a
semantic writability check (IsExpressionWritable) in
SetExpressionBinding to verify the terminal property has a public
non-init setter before generating setter code.
Fixes #34075
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
d1f6339 to
b66a712
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers
left a comment
There was a problem hiding this comment.
Besides the one question, looks good to me.
| // Strip "BindingContext." prefix (e.g., "BindingContext.Name" → "Name") | ||
| if (expr.StartsWith("BindingContext.", StringComparison.Ordinal)) | ||
| expr = expr.Substring("BindingContext.".Length); |
There was a problem hiding this comment.
Should this somehow check if it is actually BindableObject.BindingContext?
You could have a POCO that has public Person BindingContext;
There was a problem hiding this comment.
if the XAML isn't inheriting from BO... technically, yes
Address jonathanpeppers' review: a POCO could have its own `public Person BindingContext;` field. Only strip the prefix when dataType has no member named BindingContext, so it refers to BindableObject.BindingContext. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…4137) <!-- 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 Fixes #34075 The XAML source generator was generating setter assignments (e.g., `__source.ReadOnlyText = __value`) for getter-only properties when using C# expression bindings like `{ReadOnlyText}`. This caused CS0200 build errors at compile time. ### Root Cause `ExpressionAnalyzer.IsSimplePropertyChain()` only checks whether the expression is syntactically a simple property chain (member access, identifier), but does not verify whether the terminal property actually has a public setter. So `{ReadOnlyText}` where `ReadOnlyText` is `string ReadOnlyText => "Hello"` was incorrectly marked as settable. ### Fix Added `IsExpressionWritable()` in `SetPropertyHelpers.cs` that walks the property chain on the `dataType` symbol and checks whether the terminal property has a public, non-init setter. The setter lambda is only generated when both the syntactic check (`IsSettable`) and the semantic check (`IsExpressionWritable`) pass. ### Changes - `src/Controls/src/SourceGen/SetPropertyHelpers.cs` — Added `IsExpressionWritable()` helper and gated setter generation on it - `src/Controls/tests/Xaml.UnitTests/Issues/Maui34075.*` — Regression test with getter-only properties bound via C# expressions ### Testing - New `.sgen.xaml` test inflates successfully via SourceGen with read-only property bindings - Existing `NullConditionalSettable` test (two-way binding to writable properties) still passes - Existing `TwoWayDecimalBinding_UIToVM` test still passes (setter works for writable properties) --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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!
Description
Fixes #34075
The XAML source generator was generating setter assignments (e.g.,
__source.ReadOnlyText = __value) for getter-only properties when using C# expression bindings like{ReadOnlyText}. This caused CS0200 build errors at compile time.Root Cause
ExpressionAnalyzer.IsSimplePropertyChain()only checks whether the expression is syntactically a simple property chain (member access, identifier), but does not verify whether the terminal property actually has a public setter. So{ReadOnlyText}whereReadOnlyTextisstring ReadOnlyText => "Hello"was incorrectly marked as settable.Fix
Added
IsExpressionWritable()inSetPropertyHelpers.csthat walks the property chain on thedataTypesymbol and checks whether the terminal property has a public, non-init setter. The setter lambda is only generated when both the syntactic check (IsSettable) and the semantic check (IsExpressionWritable) pass.Changes
src/Controls/src/SourceGen/SetPropertyHelpers.cs— AddedIsExpressionWritable()helper and gated setter generation on itsrc/Controls/tests/Xaml.UnitTests/Issues/Maui34075.*— Regression test with getter-only properties bound via C# expressionsTesting
.sgen.xamltest inflates successfully via SourceGen with read-only property bindingsNullConditionalSettabletest (two-way binding to writable properties) still passesTwoWayDecimalBinding_UIToVMtest still passes (setter works for writable properties)