Skip to content

[XSG] Fix SourceGen typed binding setter for ObservableProperty#33914

Merged
PureWeen merged 2 commits intomainfrom
fix/sourcegen-observableproperty-setter
Feb 12, 2026
Merged

[XSG] Fix SourceGen typed binding setter for ObservableProperty#33914
PureWeen merged 2 commits intomainfrom
fix/sourcegen-observableproperty-setter

Conversation

@StephaneDelcroix
Copy link
Contributor

@StephaneDelcroix StephaneDelcroix commented Feb 5, 2026

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 a bug in SourceGen where typed bindings for properties generated by CommunityToolkit.Mvvm's [ObservableProperty] attribute were not generating setters.

Root Cause

When TryGetProperty in ITypeSymbolExtensions.cs detects an [ObservableProperty] field, it returns the property type but leaves the property output parameter as null (since the property doesn't exist in source - it's generated by CommunityToolkit).

In CompiledBindingMarkup.cs, IsWritable was checking property.SetMethod, which fails when property is null, causing setter = null to be generated for TwoWay bindings.

The Fix

  • Added isAssumedWritable out parameter to TryGetProperty
  • When ObservableProperty fallback is used, set isAssumedWritable = true
  • In CompiledBindingMarkup.cs, treat isAssumedWritable properties as writable (CommunityToolkit always generates public setters)

Reproduction

The issue can be reproduced with a ViewModel like:

public partial class MyViewModel : ObservableObject
{
    [ObservableProperty]
    private Project? _selectedProject;
}

And XAML binding:

<CollectionView SelectedItem="{Binding SelectedProject}" />

With SourceGen, the setter was null, causing TwoWay bindings to silently fail.

Testing

  • Added unit test Maui33826 that verifies the setter is generated correctly
  • Verified with real app using Appium automation

Copilot AI review requested due to automatic review settings February 5, 2026 16:06
@StephaneDelcroix StephaneDelcroix changed the title Fix SourceGen typed binding setter for ObservableProperty [XSG]Fix SourceGen typed binding setter for ObservableProperty Feb 5, 2026
@StephaneDelcroix StephaneDelcroix added this to the .NET 10.0 SR4 milestone Feb 5, 2026
@StephaneDelcroix StephaneDelcroix added the t/bug Something isn't working label Feb 5, 2026
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 fixes a bug in SourceGen where typed bindings for properties generated by CommunityToolkit.Mvvm's [ObservableProperty] attribute were not generating setters, causing TwoWay bindings to silently fail.

Changes:

  • Added isObservableProperty out parameter to TryGetProperty method to track when a property is inferred from an ObservableProperty attribute
  • Modified setter generation logic to treat ObservableProperty-generated properties as writable (they always have public setters)
  • Added comprehensive unit tests verifying both directions of TwoWay bindings with ObservableProperty

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/Controls/src/SourceGen/ITypeSymbolExtensions.cs Added method overload with isObservableProperty out parameter; maintains backward compatibility
src/Controls/src/SourceGen/CompiledBindingMarkup.cs Updated to use new isObservableProperty parameter and treat such properties as writable
src/Controls/tests/Xaml.UnitTests/Issues/Maui33826.xaml XAML test file with CollectionView using TwoWay bindings to ObservableProperty
src/Controls/tests/Xaml.UnitTests/Issues/Maui33826.xaml.cs Test code with ViewModel using [ObservableProperty] and comprehensive binding tests

When binding to a property generated by CommunityToolkit.Mvvm's
[ObservableProperty] attribute, the SourceGen typed binding was not
generating a setter. This caused TwoWay bindings to fail silently -
the SelectedItem would not update the ViewModel property.

The fix:
1. Added 'isObservableProperty' out parameter to TryGetProperty
2. When an ObservableProperty is detected, assume it's writable
   (ObservableProperty-generated properties always have a public setter)

This fixes the crash in template apps using SourceGen with
CommunityToolkit.Mvvm when tapping on CollectionView items bound
to SelectionChangedCommand with a parameter bound to the SelectedItem.

Added unit test Maui33826 to verify the fix.
Address review feedback from @simonrozsival - use more semantic
variable name that better describes the intent of the flag.
@StephaneDelcroix StephaneDelcroix force-pushed the fix/sourcegen-observableproperty-setter branch from 22e9d29 to 09eb5a2 Compare February 8, 2026 09:31
@PureWeen
Copy link
Member

PureWeen commented Feb 9, 2026

/azp run maui-pr-uitests, maui-pr-devicetests

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@StephaneDelcroix
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@PureWeen PureWeen merged commit c1e543e into main Feb 12, 2026
156 of 165 checks passed
@PureWeen PureWeen deleted the fix/sourcegen-observableproperty-setter branch February 12, 2026 00:20
TamilarasanSF4853 pushed a commit to TamilarasanSF4853/maui that referenced this pull request Mar 2, 2026
…et#33914)

> [!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 a bug in SourceGen where typed bindings for properties generated
by CommunityToolkit.Mvvm's `[ObservableProperty]` attribute were not
generating setters.

## Root Cause

When `TryGetProperty` in `ITypeSymbolExtensions.cs` detects an
`[ObservableProperty]` field, it returns the property type but leaves
the `property` output parameter as null (since the property doesn't
exist in source - it's generated by CommunityToolkit).

In `CompiledBindingMarkup.cs`, `IsWritable` was checking
`property.SetMethod`, which fails when `property` is null, causing
`setter = null` to be generated for TwoWay bindings.

## The Fix

- Added `isAssumedWritable` out parameter to `TryGetProperty`
- When ObservableProperty fallback is used, set `isAssumedWritable =
true`
- In `CompiledBindingMarkup.cs`, treat `isAssumedWritable` properties as
writable (CommunityToolkit always generates public setters)

## Reproduction

The issue can be reproduced with a ViewModel like:
```csharp
public partial class MyViewModel : ObservableObject
{
    [ObservableProperty]
    private Project? _selectedProject;
}
```

And XAML binding:
```xml
<CollectionView SelectedItem="{Binding SelectedProject}" />
```

With SourceGen, the setter was null, causing TwoWay bindings to silently
fail.

## Testing

- Added unit test `Maui33826` that verifies the setter is generated
correctly
- Verified with real app using Appium automation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

copilot t/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants