Skip to content

Conversation

@simonrozsival
Copy link
Member

Description of Change

Consider the following scenario:

public partial class TestPage : ContentPage
{
	public Product? Product { get; set; } = null;
	public TestPage()
	{
		InitializeComponent();
	}
}
public class Product
{
	public int Size { get; set; }
}
<ContentPage xmlns:test="clr-namespace:Test" x:Class="Test.TestPage"
    Title="{Binding Product.Size, x:DataType=test:TestPage}"/>

The property accessed by the binding is Size which is an int. The Product property on the TestPage is nullable though. The getter expression looks like this:

Func<TestPage, int> getter = static source => source.Product?.Size;

This is a problem, as the conditional access to the Product value changes the property type from int to int?. There were two options I was considering:

  • change the typed binding property type from int to int?
  • unwrap the expression value with fallback to the TargetNullValue (if available) or the default value

I chose the second, since the first option would not use TargetNullValue at all. Feedback is welcome.

Issues Fixed

Contributes to #32398

Copilot AI review requested due to automatic review settings November 5, 2025 13:28
@simonrozsival simonrozsival added the area-xaml XAML, CSS, Triggers, Behaviors label Nov 5, 2025
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 enhances the compiled bindings source generator to correctly handle nullable types in binding paths. When a binding path contains nullable intermediate types leading to non-nullable value types, the generator now produces code that properly handles null propagation with fallback to TargetNullValue or default.

Key Changes

  • Modified getter lambda generation to detect conditional access patterns and non-nullable value type targets
  • Added null-coalescing fallback logic to unwrap nullable value types when the binding path contains nullable references

Reviewed Changes

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

File Description
src/Controls/src/SourceGen/CompiledBindingMarkup.cs Enhanced GenerateGetterLambda to detect conditional access and generate appropriate null-coalescing expressions for non-nullable value types
src/Controls/tests/SourceGen.UnitTests/InitializeComponent/CompiledBindings.cs Added comprehensive test case verifying correct code generation for nullable reference types leading to non-nullable value types

@dainius-r
Copy link

@simonrozsival related question:
We have public Product[] Product { get; set; } = []; empty array of products.
And we have this binding expression Title="{Binding Product[0].Size, x:DataType=test:TestPage}".
How to use binding without getting exception index out of range, can similar TargetNullValue be used?

@StephaneDelcroix
Copy link
Contributor

/azp run MAUI-UITests-public

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@simonrozsival
Copy link
Member Author

How to use binding without getting exception index out of range, can similar TargetNullValue be used?

@dainius-r with indexers it's going to be a bit more tricky. I would suggest doing this a bit more manually and defining a new property in the view model:

public Product FirstProduct => Product.Length > 0 ? Product[0] : someFallbackValue;

Now based on your sample it doesn't seem you publish any PropertyChanged events for the Product property and its items, but you could and if you do, you should also raise an event for FirstProduct.

@StephaneDelcroix StephaneDelcroix added this to the .NET 10.0 SR1 milestone Nov 6, 2025
@simonrozsival simonrozsival enabled auto-merge (squash) November 6, 2025 12:07
@simonrozsival simonrozsival merged commit c9d5028 into main Nov 6, 2025
163 checks passed
@simonrozsival simonrozsival deleted the dev/srozsival/fix-xsg-compiled-bindings-conditional-access-to-non-nullable-value-types branch November 6, 2025 12:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-xaml XAML, CSS, Triggers, Behaviors

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants