Skip to content

Fix XAML C# expression setter generation for read-only properties#34137

Merged
StephaneDelcroix merged 3 commits intomainfrom
fix/34075-readonly-expression-binding
Feb 26, 2026
Merged

Fix XAML C# expression setter generation for read-only properties#34137
StephaneDelcroix merged 3 commits intomainfrom
fix/34075-readonly-expression-binding

Conversation

@StephaneDelcroix
Copy link
Copy Markdown
Contributor

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} 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)

Copilot AI review requested due to automatic review settings February 19, 2026 13:23
Copy link
Copy Markdown
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 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.AI library 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>
@StephaneDelcroix StephaneDelcroix force-pushed the fix/34075-readonly-expression-binding branch from d1f6339 to b66a712 Compare February 24, 2026 13:49
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member

@jonathanpeppers jonathanpeppers left a comment

Choose a reason for hiding this comment

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

Besides the one question, looks good to me.

Comment on lines +938 to +940
// Strip "BindingContext." prefix (e.g., "BindingContext.Name" → "Name")
if (expr.StartsWith("BindingContext.", StringComparison.Ordinal))
expr = expr.Substring("BindingContext.".Length);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this somehow check if it is actually BindableObject.BindingContext?

You could have a POCO that has public Person BindingContext;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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>
@StephaneDelcroix StephaneDelcroix merged commit eba391e into main Feb 26, 2026
24 of 27 checks passed
@StephaneDelcroix StephaneDelcroix deleted the fix/34075-readonly-expression-binding branch February 26, 2026 06:37
Tamilarasan-Paranthaman pushed a commit that referenced this pull request Mar 2, 2026
…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>
@github-actions github-actions Bot locked and limited conversation to collaborators Mar 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

XAML C# expression tries to assign a value to the read-only properties, but it should be based on the binding mode

4 participants