Skip to content

[XSG][BindingSourceGen] Add support for CommunityToolkit.Mvvm ObservablePropertyAttribute#33028

Merged
PureWeen merged 15 commits intoinflight/currentfrom
copilot/add-observable-property-support
Jan 14, 2026
Merged

[XSG][BindingSourceGen] Add support for CommunityToolkit.Mvvm ObservablePropertyAttribute#33028
PureWeen merged 15 commits intoinflight/currentfrom
copilot/add-observable-property-support

Conversation

Copy link
Contributor

Copilot AI commented Dec 6, 2025

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 of Change

Binding source generators now support properties generated by CommunityToolkit.Mvvm's [ObservableProperty] attribute. Previously, bindings failed because MAUI generators cannot see properties generated by other source generators.

Implementation (following PR #32954 pattern for RelayCommand):

  • BindingSourceGen/ITypeSymbolExtensions.cs: Added TryGetObservablePropertyType() to detect fields with [ObservableProperty] and infer property types. Supports all three documented field naming patterns: camelCase, _camelCase, and m_camelCase. Includes validation for empty property names.

  • BindingSourceGen/PathParser.cs: Enhanced TryHandleSpecialCases() to handle ObservableProperty patterns as fallback when symbol resolution fails.

  • BindingSourceGen/BindingSourceGenerator.cs: Updated GetLambdaReturnType() to infer types from ObservableProperty fields, enabling C# lambda bindings.

  • SourceGen/ITypeSymbolExtensions.cs: Updated TryGetProperty() to check ObservableProperty-inferred properties, enabling XAML string-based bindings.

  • Tests: Added comprehensive unit tests in BindingSourceGen.UnitTests (8 tests) to validate ObservableProperty binding support across all field naming patterns and scenarios. Tests verify the generated binding code by checking:

    • Handler patterns: new(static source => source, "PropertyName") - validates property path in generated code
    • Setter expressions: source.PropertyName = value; - validates property assignment

Field Naming Pattern Support:

All three CommunityToolkit.Mvvm documented naming conventions are supported:

  • nameName
  • _nameName
  • m_nameName

Works for both XAML and C# bindings:

public class MyViewModel
{
    [ObservableProperty]
    private string? name;  // Generates Name property
    
    [ObservableProperty]
    private ObservableCollection<Tag> _tags = new();  // Generates Tags property
    
    [ObservableProperty]
    private int m_count;  // Generates Count property
}
<Label Text="{Binding Name}" />
<ListView ItemsSource="{Binding Tags}" />
label.SetBinding(Label.TextProperty, static (MyViewModel vm) => vm.Name);
listView.SetBinding(ListView.ItemsSourceProperty, static (MyViewModel vm) => vm.Tags);

Issues Fixed

Fixes #32597

Original prompt

This section details on the original issue you should resolve

<issue_title>[XSG][BindingSourceGen] Add support for CommunityToolkit.Mvvm ObservablePropertyAttribute source generator</issue_title>
<issue_description>Similar to #32597
Related to #32953

The CommunityToolkit.Mvvm package contains a source generator which generates bindable property bolierplate code based on the [ObservableProperty] attribute: https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/observableproperty

Scenarios:

// applied to a field
[ObservableProperty]
private string? name;

// generated code:
/// <inheritdoc cref="_tags"/>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.3.0.0")]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag> Tags
{
    get => _tags;
    [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_tags")]
    set
    {
        if (!global::System.Collections.Generic.EqualityComparer<global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>>.Default.Equals(_tags, value))
        {
            OnTagsChanging(value);
            OnTagsChanging(default, value);
            OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Tags);
            _tags = value;
            OnTagsChanged(value);
            OnTagsChanged(default, value);
            OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Tags);
        }
    }
}

Our source generators cannot see properties generated by other source generators, so the binding compilation will fail.

Our sample content template uses this source generator and we are currently failing over to reflection-based bindings.</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Add support for CommunityToolkit.Mvvm ObservablePropertyAttribute generator [XSG][BindingSourceGen] Add support for CommunityToolkit.Mvvm ObservablePropertyAttribute Dec 6, 2025
Copilot AI requested a review from simonrozsival December 6, 2025 23:18
@simonrozsival
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines could not run because the pipeline triggers exclude this branch/path.

@simonrozsival simonrozsival force-pushed the copilot/add-observable-property-support branch from 6c9d40b to c039c1f Compare December 8, 2025 17:44
@simonrozsival
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines could not run because the pipeline triggers exclude this branch/path.

Copy link
Member

@simonrozsival simonrozsival left a comment

Choose a reason for hiding this comment

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

@copilot please add also a test case in Xaml.UnitTest

Copy link
Contributor Author

Copilot AI commented Dec 8, 2025

@copilot please add also a test case in Xaml.UnitTest

Added XAML unit tests in commit 5a2eadd. The tests cover bindings to ObservableProperty-generated properties from camelCase fields (nameName), underscore-prefixed fields (_titleTitle), and collections (_tagsTags). Tests validate all three XamlInflator modes (Runtime, XamlC, SourceGen).

Copy link
Member

@simonrozsival simonrozsival left a comment

Choose a reason for hiding this comment

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

@copilot please address these comments

Copy link
Contributor Author

Copilot AI commented Dec 9, 2025

@copilot please address these comments

All code review feedback addressed in commit bf6d334:

  • Added empty propertyName check
  • Added m_ prefix support
  • Simplified GetAllFields method
  • Improved test assertions to check getter/setter expressions
  • Added test for m_ prefix

XAML unit tests remain reverted as they don't test the actual code without CommunityToolkit.Mvvm source generator.

Copy link
Member

@simonrozsival simonrozsival left a comment

Choose a reason for hiding this comment

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

@copilot address these comments

Copy link
Contributor Author

Copilot AI commented Dec 9, 2025

@copilot address these comments

Fixed test assertions to check handler patterns instead of method signatures in commit 80bcfb1. All tests passing.

Copilot AI requested a review from simonrozsival December 9, 2025 09:08
@simonrozsival simonrozsival force-pushed the copilot/add-observable-property-support branch from 80bcfb1 to a39fcbc Compare December 11, 2025 12:27
@simonrozsival simonrozsival force-pushed the copilot/add-observable-property-support branch from 0f4fd5c to df71ebb Compare January 12, 2026 09:43
Copilot AI and others added 15 commits January 14, 2026 16:19
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
- Add empty propertyName check (comment 2601388315)
- Add m_ prefix support for field naming (comment 2601414955)
- Simplify GetAllFields to use unified while+foreach (comment 2601399294)
- Improve test assertions to check getter/setter in generated code (comments 2601422688, 2601424822, 2601426465)
- Add test for m_ prefix support

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
- Check for handler pattern: new(static source => source, "PropertyName")
- This is the useful assertion that validates property path in generated code
- Updated all three ObservableProperty tests (Name, Title, Tags)

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
@PureWeen PureWeen force-pushed the copilot/add-observable-property-support branch from df71ebb to cb00d50 Compare January 14, 2026 22:21
@PureWeen PureWeen merged commit 03971db into inflight/current Jan 14, 2026
1 of 2 checks passed
@PureWeen PureWeen deleted the copilot/add-observable-property-support branch January 14, 2026 22:21
github-actions bot pushed a commit that referenced this pull request Jan 16, 2026
…blePropertyAttribute (#33028)

> [!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 of Change

Binding source generators now support properties generated by
CommunityToolkit.Mvvm's `[ObservableProperty]` attribute. Previously,
bindings failed because MAUI generators cannot see properties generated
by other source generators.

**Implementation** (following PR #32954 pattern for RelayCommand):

- **BindingSourceGen/ITypeSymbolExtensions.cs**: Added
`TryGetObservablePropertyType()` to detect fields with
`[ObservableProperty]` and infer property types. Supports all three
documented field naming patterns: `camelCase`, `_camelCase`, and
`m_camelCase`. Includes validation for empty property names.

- **BindingSourceGen/PathParser.cs**: Enhanced `TryHandleSpecialCases()`
to handle ObservableProperty patterns as fallback when symbol resolution
fails.

- **BindingSourceGen/BindingSourceGenerator.cs**: Updated
`GetLambdaReturnType()` to infer types from ObservableProperty fields,
enabling C# lambda bindings.

- **SourceGen/ITypeSymbolExtensions.cs**: Updated `TryGetProperty()` to
check ObservableProperty-inferred properties, enabling XAML string-based
bindings.

- **Tests**: Added comprehensive unit tests in
`BindingSourceGen.UnitTests` (8 tests) to validate ObservableProperty
binding support across all field naming patterns and scenarios. Tests
verify the generated binding code by checking:
- Handler patterns: `new(static source => source, "PropertyName")` -
validates property path in generated code
- Setter expressions: `source.PropertyName = value;` - validates
property assignment

**Field Naming Pattern Support:**

All three CommunityToolkit.Mvvm documented naming conventions are
supported:
- `name` → `Name`
- `_name` → `Name`
- `m_name` → `Name`

**Works for both XAML and C# bindings:**

```csharp
public class MyViewModel
{
    [ObservableProperty]
    private string? name;  // Generates Name property
    
    [ObservableProperty]
    private ObservableCollection<Tag> _tags = new();  // Generates Tags property
    
    [ObservableProperty]
    private int m_count;  // Generates Count property
}
```

```xaml
<Label Text="{Binding Name}" />
<ListView ItemsSource="{Binding Tags}" />
```

```csharp
label.SetBinding(Label.TextProperty, static (MyViewModel vm) => vm.Name);
listView.SetBinding(ListView.ItemsSourceProperty, static (MyViewModel vm) => vm.Tags);
```

### Issues Fixed

Fixes #32597

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[XSG][BindingSourceGen] Add support for
CommunityToolkit.Mvvm ObservablePropertyAttribute source
generator</issue_title>
> <issue_description>Similar to #32597
> Related to #32953
> 
> The CommunityToolkit.Mvvm package contains a source generator which
generates bindable property bolierplate code based on the
`[ObservableProperty]` attribute:
https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/observableproperty
> 
> Scenarios:
> ```c#
> // applied to a field
> [ObservableProperty]
> private string? name;
> 
> // generated code:
> /// <inheritdoc cref="_tags"/>
>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator",
"8.3.0.0")]
> [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
> public
global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>
Tags
> {
>     get => _tags;
>     [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_tags")]
>     set
>     {
> if
(!global::System.Collections.Generic.EqualityComparer<global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>>.Default.Equals(_tags,
value))
>         {
>             OnTagsChanging(value);
>             OnTagsChanging(default, value);
>
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Tags);
>             _tags = value;
>             OnTagsChanged(value);
>             OnTagsChanged(default, value);
>
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Tags);
>         }
>     }
> }
> ```
> 
> Our source generators cannot see properties generated by other source
generators, so the binding compilation will fail.
> 
> Our sample content template uses this source generator and we are
currently failing over to reflection-based bindings.</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #32955

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Co-authored-by: Simon Rozsival <simon@rozsival.com>
github-actions bot pushed a commit that referenced this pull request Jan 20, 2026
…blePropertyAttribute (#33028)

> [!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 of Change

Binding source generators now support properties generated by
CommunityToolkit.Mvvm's `[ObservableProperty]` attribute. Previously,
bindings failed because MAUI generators cannot see properties generated
by other source generators.

**Implementation** (following PR #32954 pattern for RelayCommand):

- **BindingSourceGen/ITypeSymbolExtensions.cs**: Added
`TryGetObservablePropertyType()` to detect fields with
`[ObservableProperty]` and infer property types. Supports all three
documented field naming patterns: `camelCase`, `_camelCase`, and
`m_camelCase`. Includes validation for empty property names.

- **BindingSourceGen/PathParser.cs**: Enhanced `TryHandleSpecialCases()`
to handle ObservableProperty patterns as fallback when symbol resolution
fails.

- **BindingSourceGen/BindingSourceGenerator.cs**: Updated
`GetLambdaReturnType()` to infer types from ObservableProperty fields,
enabling C# lambda bindings.

- **SourceGen/ITypeSymbolExtensions.cs**: Updated `TryGetProperty()` to
check ObservableProperty-inferred properties, enabling XAML string-based
bindings.

- **Tests**: Added comprehensive unit tests in
`BindingSourceGen.UnitTests` (8 tests) to validate ObservableProperty
binding support across all field naming patterns and scenarios. Tests
verify the generated binding code by checking:
- Handler patterns: `new(static source => source, "PropertyName")` -
validates property path in generated code
- Setter expressions: `source.PropertyName = value;` - validates
property assignment

**Field Naming Pattern Support:**

All three CommunityToolkit.Mvvm documented naming conventions are
supported:
- `name` → `Name`
- `_name` → `Name`
- `m_name` → `Name`

**Works for both XAML and C# bindings:**

```csharp
public class MyViewModel
{
    [ObservableProperty]
    private string? name;  // Generates Name property
    
    [ObservableProperty]
    private ObservableCollection<Tag> _tags = new();  // Generates Tags property
    
    [ObservableProperty]
    private int m_count;  // Generates Count property
}
```

```xaml
<Label Text="{Binding Name}" />
<ListView ItemsSource="{Binding Tags}" />
```

```csharp
label.SetBinding(Label.TextProperty, static (MyViewModel vm) => vm.Name);
listView.SetBinding(ListView.ItemsSourceProperty, static (MyViewModel vm) => vm.Tags);
```

### Issues Fixed

Fixes #32597

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[XSG][BindingSourceGen] Add support for
CommunityToolkit.Mvvm ObservablePropertyAttribute source
generator</issue_title>
> <issue_description>Similar to #32597
> Related to #32953
> 
> The CommunityToolkit.Mvvm package contains a source generator which
generates bindable property bolierplate code based on the
`[ObservableProperty]` attribute:
https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/observableproperty
> 
> Scenarios:
> ```c#
> // applied to a field
> [ObservableProperty]
> private string? name;
> 
> // generated code:
> /// <inheritdoc cref="_tags"/>
>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator",
"8.3.0.0")]
> [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
> public
global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>
Tags
> {
>     get => _tags;
>     [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_tags")]
>     set
>     {
> if
(!global::System.Collections.Generic.EqualityComparer<global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>>.Default.Equals(_tags,
value))
>         {
>             OnTagsChanging(value);
>             OnTagsChanging(default, value);
>
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Tags);
>             _tags = value;
>             OnTagsChanged(value);
>             OnTagsChanged(default, value);
>
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Tags);
>         }
>     }
> }
> ```
> 
> Our source generators cannot see properties generated by other source
generators, so the binding compilation will fail.
> 
> Our sample content template uses this source generator and we are
currently failing over to reflection-based bindings.</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #32955

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Co-authored-by: Simon Rozsival <simon@rozsival.com>
github-actions bot pushed a commit that referenced this pull request Jan 21, 2026
…blePropertyAttribute (#33028)

> [!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 of Change

Binding source generators now support properties generated by
CommunityToolkit.Mvvm's `[ObservableProperty]` attribute. Previously,
bindings failed because MAUI generators cannot see properties generated
by other source generators.

**Implementation** (following PR #32954 pattern for RelayCommand):

- **BindingSourceGen/ITypeSymbolExtensions.cs**: Added
`TryGetObservablePropertyType()` to detect fields with
`[ObservableProperty]` and infer property types. Supports all three
documented field naming patterns: `camelCase`, `_camelCase`, and
`m_camelCase`. Includes validation for empty property names.

- **BindingSourceGen/PathParser.cs**: Enhanced `TryHandleSpecialCases()`
to handle ObservableProperty patterns as fallback when symbol resolution
fails.

- **BindingSourceGen/BindingSourceGenerator.cs**: Updated
`GetLambdaReturnType()` to infer types from ObservableProperty fields,
enabling C# lambda bindings.

- **SourceGen/ITypeSymbolExtensions.cs**: Updated `TryGetProperty()` to
check ObservableProperty-inferred properties, enabling XAML string-based
bindings.

- **Tests**: Added comprehensive unit tests in
`BindingSourceGen.UnitTests` (8 tests) to validate ObservableProperty
binding support across all field naming patterns and scenarios. Tests
verify the generated binding code by checking:
- Handler patterns: `new(static source => source, "PropertyName")` -
validates property path in generated code
- Setter expressions: `source.PropertyName = value;` - validates
property assignment

**Field Naming Pattern Support:**

All three CommunityToolkit.Mvvm documented naming conventions are
supported:
- `name` → `Name`
- `_name` → `Name`
- `m_name` → `Name`

**Works for both XAML and C# bindings:**

```csharp
public class MyViewModel
{
    [ObservableProperty]
    private string? name;  // Generates Name property
    
    [ObservableProperty]
    private ObservableCollection<Tag> _tags = new();  // Generates Tags property
    
    [ObservableProperty]
    private int m_count;  // Generates Count property
}
```

```xaml
<Label Text="{Binding Name}" />
<ListView ItemsSource="{Binding Tags}" />
```

```csharp
label.SetBinding(Label.TextProperty, static (MyViewModel vm) => vm.Name);
listView.SetBinding(ListView.ItemsSourceProperty, static (MyViewModel vm) => vm.Tags);
```

### Issues Fixed

Fixes #32597

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[XSG][BindingSourceGen] Add support for
CommunityToolkit.Mvvm ObservablePropertyAttribute source
generator</issue_title>
> <issue_description>Similar to #32597
> Related to #32953
> 
> The CommunityToolkit.Mvvm package contains a source generator which
generates bindable property bolierplate code based on the
`[ObservableProperty]` attribute:
https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/observableproperty
> 
> Scenarios:
> ```c#
> // applied to a field
> [ObservableProperty]
> private string? name;
> 
> // generated code:
> /// <inheritdoc cref="_tags"/>
>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator",
"8.3.0.0")]
> [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
> public
global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>
Tags
> {
>     get => _tags;
>     [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_tags")]
>     set
>     {
> if
(!global::System.Collections.Generic.EqualityComparer<global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>>.Default.Equals(_tags,
value))
>         {
>             OnTagsChanging(value);
>             OnTagsChanging(default, value);
>
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Tags);
>             _tags = value;
>             OnTagsChanged(value);
>             OnTagsChanged(default, value);
>
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Tags);
>         }
>     }
> }
> ```
> 
> Our source generators cannot see properties generated by other source
generators, so the binding compilation will fail.
> 
> Our sample content template uses this source generator and we are
currently failing over to reflection-based bindings.</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #32955

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Co-authored-by: Simon Rozsival <simon@rozsival.com>
github-actions bot pushed a commit that referenced this pull request Jan 23, 2026
…blePropertyAttribute (#33028)

> [!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 of Change

Binding source generators now support properties generated by
CommunityToolkit.Mvvm's `[ObservableProperty]` attribute. Previously,
bindings failed because MAUI generators cannot see properties generated
by other source generators.

**Implementation** (following PR #32954 pattern for RelayCommand):

- **BindingSourceGen/ITypeSymbolExtensions.cs**: Added
`TryGetObservablePropertyType()` to detect fields with
`[ObservableProperty]` and infer property types. Supports all three
documented field naming patterns: `camelCase`, `_camelCase`, and
`m_camelCase`. Includes validation for empty property names.

- **BindingSourceGen/PathParser.cs**: Enhanced `TryHandleSpecialCases()`
to handle ObservableProperty patterns as fallback when symbol resolution
fails.

- **BindingSourceGen/BindingSourceGenerator.cs**: Updated
`GetLambdaReturnType()` to infer types from ObservableProperty fields,
enabling C# lambda bindings.

- **SourceGen/ITypeSymbolExtensions.cs**: Updated `TryGetProperty()` to
check ObservableProperty-inferred properties, enabling XAML string-based
bindings.

- **Tests**: Added comprehensive unit tests in
`BindingSourceGen.UnitTests` (8 tests) to validate ObservableProperty
binding support across all field naming patterns and scenarios. Tests
verify the generated binding code by checking:
- Handler patterns: `new(static source => source, "PropertyName")` -
validates property path in generated code
- Setter expressions: `source.PropertyName = value;` - validates
property assignment

**Field Naming Pattern Support:**

All three CommunityToolkit.Mvvm documented naming conventions are
supported:
- `name` → `Name`
- `_name` → `Name`
- `m_name` → `Name`

**Works for both XAML and C# bindings:**

```csharp
public class MyViewModel
{
    [ObservableProperty]
    private string? name;  // Generates Name property
    
    [ObservableProperty]
    private ObservableCollection<Tag> _tags = new();  // Generates Tags property
    
    [ObservableProperty]
    private int m_count;  // Generates Count property
}
```

```xaml
<Label Text="{Binding Name}" />
<ListView ItemsSource="{Binding Tags}" />
```

```csharp
label.SetBinding(Label.TextProperty, static (MyViewModel vm) => vm.Name);
listView.SetBinding(ListView.ItemsSourceProperty, static (MyViewModel vm) => vm.Tags);
```

### Issues Fixed

Fixes #32597

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[XSG][BindingSourceGen] Add support for
CommunityToolkit.Mvvm ObservablePropertyAttribute source
generator</issue_title>
> <issue_description>Similar to #32597
> Related to #32953
> 
> The CommunityToolkit.Mvvm package contains a source generator which
generates bindable property bolierplate code based on the
`[ObservableProperty]` attribute:
https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/observableproperty
> 
> Scenarios:
> ```c#
> // applied to a field
> [ObservableProperty]
> private string? name;
> 
> // generated code:
> /// <inheritdoc cref="_tags"/>
>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator",
"8.3.0.0")]
> [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
> public
global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>
Tags
> {
>     get => _tags;
>     [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_tags")]
>     set
>     {
> if
(!global::System.Collections.Generic.EqualityComparer<global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>>.Default.Equals(_tags,
value))
>         {
>             OnTagsChanging(value);
>             OnTagsChanging(default, value);
>
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Tags);
>             _tags = value;
>             OnTagsChanged(value);
>             OnTagsChanged(default, value);
>
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Tags);
>         }
>     }
> }
> ```
> 
> Our source generators cannot see properties generated by other source
generators, so the binding compilation will fail.
> 
> Our sample content template uses this source generator and we are
currently failing over to reflection-based bindings.</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #32955

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Co-authored-by: Simon Rozsival <simon@rozsival.com>
PureWeen pushed a commit that referenced this pull request Jan 23, 2026
…blePropertyAttribute (#33028)

> [!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 of Change

Binding source generators now support properties generated by
CommunityToolkit.Mvvm's `[ObservableProperty]` attribute. Previously,
bindings failed because MAUI generators cannot see properties generated
by other source generators.

**Implementation** (following PR #32954 pattern for RelayCommand):

- **BindingSourceGen/ITypeSymbolExtensions.cs**: Added
`TryGetObservablePropertyType()` to detect fields with
`[ObservableProperty]` and infer property types. Supports all three
documented field naming patterns: `camelCase`, `_camelCase`, and
`m_camelCase`. Includes validation for empty property names.

- **BindingSourceGen/PathParser.cs**: Enhanced `TryHandleSpecialCases()`
to handle ObservableProperty patterns as fallback when symbol resolution
fails.

- **BindingSourceGen/BindingSourceGenerator.cs**: Updated
`GetLambdaReturnType()` to infer types from ObservableProperty fields,
enabling C# lambda bindings.

- **SourceGen/ITypeSymbolExtensions.cs**: Updated `TryGetProperty()` to
check ObservableProperty-inferred properties, enabling XAML string-based
bindings.

- **Tests**: Added comprehensive unit tests in
`BindingSourceGen.UnitTests` (8 tests) to validate ObservableProperty
binding support across all field naming patterns and scenarios. Tests
verify the generated binding code by checking:
- Handler patterns: `new(static source => source, "PropertyName")` -
validates property path in generated code
- Setter expressions: `source.PropertyName = value;` - validates
property assignment

**Field Naming Pattern Support:**

All three CommunityToolkit.Mvvm documented naming conventions are
supported:
- `name` → `Name`
- `_name` → `Name`
- `m_name` → `Name`

**Works for both XAML and C# bindings:**

```csharp
public class MyViewModel
{
    [ObservableProperty]
    private string? name;  // Generates Name property
    
    [ObservableProperty]
    private ObservableCollection<Tag> _tags = new();  // Generates Tags property
    
    [ObservableProperty]
    private int m_count;  // Generates Count property
}
```

```xaml
<Label Text="{Binding Name}" />
<ListView ItemsSource="{Binding Tags}" />
```

```csharp
label.SetBinding(Label.TextProperty, static (MyViewModel vm) => vm.Name);
listView.SetBinding(ListView.ItemsSourceProperty, static (MyViewModel vm) => vm.Tags);
```

### Issues Fixed

Fixes #32597

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[XSG][BindingSourceGen] Add support for
CommunityToolkit.Mvvm ObservablePropertyAttribute source
generator</issue_title>
> <issue_description>Similar to #32597
> Related to #32953
> 
> The CommunityToolkit.Mvvm package contains a source generator which
generates bindable property bolierplate code based on the
`[ObservableProperty]` attribute:
https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/observableproperty
> 
> Scenarios:
> ```c#
> // applied to a field
> [ObservableProperty]
> private string? name;
> 
> // generated code:
> /// <inheritdoc cref="_tags"/>
>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator",
"8.3.0.0")]
> [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
> public
global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>
Tags
> {
>     get => _tags;
>     [global::System.Diagnostics.CodeAnalysis.MemberNotNull("_tags")]
>     set
>     {
> if
(!global::System.Collections.Generic.EqualityComparer<global::System.Collections.ObjectModel.ObservableCollection<global::TestSampleContentBindings.Models.Tag>>.Default.Equals(_tags,
value))
>         {
>             OnTagsChanging(value);
>             OnTagsChanging(default, value);
>
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Tags);
>             _tags = value;
>             OnTagsChanged(value);
>             OnTagsChanged(default, value);
>
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Tags);
>         }
>     }
> }
> ```
> 
> Our source generators cannot see properties generated by other source
generators, so the binding compilation will fail.
> 
> Our sample content template uses this source generator and we are
currently failing over to reflection-based bindings.</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #32955

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Co-authored-by: Simon Rozsival <simon@rozsival.com>
PureWeen added a commit that referenced this pull request Jan 25, 2026
## What's Coming

.NET MAUI inflight/candidate introduces significant improvements across
all platforms with focus on quality, performance, and developer
experience. This release includes 16 commits with various improvements,
bug fixes, and enhancements.


## Checkbox
- [Android] Implement material3 support for CheckBox by
@HarishwaranVijayakumar in #33339
  <details>
  <summary>🔧 Fixes</summary>

- [Implement Material3 Support for
CheckBox](#33338)
  </details>

## CollectionView
- [Android] Fixed EmptyView doesn’t display when CollectionView is
placed inside a VerticalStackLayout by @NanthiniMahalingam in
#33134
  <details>
  <summary>🔧 Fixes</summary>

- [CollectionView does not show an EmptyView template with an empty
collection](#32932)
  </details>

## Essentials
- [Windows]Fix NullReferenceException in OpenReadAsync for FileResult
created with full path by @devanathan-vaithiyanathan in
#28238
  <details>
  <summary>🔧 Fixes</summary>

- [[Windows] FileResult(string fullPath) not initialized
properly](#26858)
  </details>

## Image
- Fix Glide IllegalArgumentException in MauiCustomTarget.clear() for
destroyed activities by @jfversluis via @Copilot in
#29780
  <details>
  <summary>🔧 Fixes</summary>

- [java.lang.IllegalArgumentException: You cannot start a load for a
destroyed activity - glide](#29699)
  </details>

## Label
- [Android] Fix for Label WordWrap width issue causing HorizontalOptions
misalignment by @praveenkumarkarunanithi in
#33281
  <details>
  <summary>🔧 Fixes</summary>

- [[Android] Unexpected Line Breaks in Android, Label with WordWrap Mode
Due to Trailing Space.](#31782)
- [Label not sized correctly on
Android](#27614)
  </details>

- Fix to Improve Flyout Accessibility by Adjusting UITableViewController
Labels by @SuthiYuvaraj in #31619
  <details>
  <summary>🔧 Fixes</summary>

- [Navigation section present under hamburger are programmatically
define as table :A11y_.NET maui_User can get all the insights of
Dashboard_Devtools](#30894)
  </details>

## Mediapicker
- [Regression][iOS] Fix MediaPicker PickPhotosAsync getting file name in
contentType property by @devanathan-vaithiyanathan in
#33390
  <details>
  <summary>🔧 Fixes</summary>

- [[iOS] MediaPicker PickPhotosAsync getting file name in contentType
property](#33348)
  </details>

## Navigation
- Fix handler not disconnected when removing non visible pages using
RemovePage() by @Vignesh-SF3580 in
#32289
  <details>
  <summary>🔧 Fixes</summary>

- [NavigationPage.Navigation.RemovePage() fails to disconnect handlers
when removing pages, unlike
ContentPage.Navigation.RemovePage()](#32239)
  </details>

## Picker
- [Android] Fix Picker IsOpen not reset when picker is dismissed by
@devanathan-vaithiyanathan in #33332
  <details>
  <summary>🔧 Fixes</summary>

- [[Android] Picker IsOpen not reset when picker is
dismissed](#33331)
  </details>

## Shell
- [iOS & Catalyst ] Fixed IsEnabled property should work on Tabs by
@SubhikshaSf4851 in #33369
  <details>
  <summary>🔧 Fixes</summary>

- [[Catalyst] TabBarBackgroundColor, TabBarUnselectedColor, and
IsEnabled Not Working as Expected in
Shell](#33158)
  </details>

- [iOS,Windows] Fix navigation bar colors not resetting when switching
ShellContent by @Vignesh-SF3580 in
#33228
  <details>
  <summary>🔧 Fixes</summary>

- [[iOS, Windows] Shell Navigation bar colors are not updated correctly
when switching
ShellContent](#33227)
  </details>

- [iOS] Fixed Shell navigation on search handler suggestion selection by
@SubhikshaSf4851 in #33406
  <details>
  <summary>🔧 Fixes</summary>

- [[iOS] Clicking on search suggestions fails to navigate to detail page
correctly](#33356)
  </details>

## Templates
- Fix VoiceOver doesnot announces the State of the ComboBox by
@SuthiYuvaraj in #32286

## Xaml
- [XSG][BindingSourceGen] Add support for CommunityToolkit.Mvvm
ObservablePropertyAttribute by @simonrozsival via @Copilot in
#33028
  <details>
  <summary>🔧 Fixes</summary>

- [[XSG] Add heuristic to support bindable properties generated by other
source generators](#32597)
  </details>


<details>
<summary>📦 Other (2)</summary>

- [XSG] Improve diagnostic reporting during binding compilation by
@simonrozsival via @Copilot in #32905
- [Testing] Fixed Test case failure in PR 33574 - [01/19/2026] Candidate
- 1 by @TamilarasanSF4853 in #33602

</details>
**Full Changelog**:
main...inflight/candidate
@github-actions github-actions bot locked and limited conversation to collaborators Feb 14, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Comments