@@ -181,6 +181,181 @@ static bool ShouldUseSetter(global::Microsoft.Maui.Controls.BindingMode mode)
181181 }
182182}
183183
184+ """ ;
185+
186+ var ( result , generated ) = RunGenerator ( xaml , code ) ;
187+ Assert . False ( result . Diagnostics . Any ( ) ) ;
188+ Assert . Equal ( expected , generated , ignoreLineEndingDifferences : true ) ;
189+ }
190+
191+ [ Fact ]
192+ public void CorrectlyDetectsNullableTypes ( )
193+ {
194+ var xaml =
195+ """
196+ <?xml version="1.0" encoding="UTF-8"?>
197+ <ContentPage
198+ xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
199+ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
200+ xmlns:test="clr-namespace:Test"
201+ x:Class="Test.TestPage"
202+ x:DataType="test:TestPage"
203+ Title="{Binding Product.Size}"/>
204+ """ ;
205+
206+ var code =
207+ """
208+ #nullable enable
209+ using System;
210+ using Microsoft.Maui.Controls;
211+ using Microsoft.Maui.Controls.Xaml;
212+
213+ namespace Test;
214+
215+ [XamlProcessing(XamlInflator.SourceGen)]
216+ public partial class TestPage : ContentPage
217+ {
218+ public Product? Product { get; set; } = null;
219+
220+ public TestPage()
221+ {
222+ InitializeComponent();
223+ }
224+ }
225+
226+ public class Product
227+ {
228+ public int Size { get; set; }
229+ }
230+ """ ;
231+ var testXamlFilePath = Path . Combine ( Environment . CurrentDirectory , "Test.xaml" ) ;
232+ var expected = $$ """
233+ //------------------------------------------------------------------------------
234+ // <auto-generated>
235+ // This code was generated by a .NET MAUI source generator.
236+ //
237+ // Changes to this file may cause incorrect behavior and will be lost if
238+ // the code is regenerated.
239+ // </auto-generated>
240+ //------------------------------------------------------------------------------
241+ #nullable enable
242+
243+ namespace Test;
244+
245+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Maui.Controls.SourceGen, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null", "10.0.0.0")]
246+ public partial class TestPage
247+ {
248+ private partial void InitializeComponent()
249+ {
250+ // Fallback to Runtime inflation if the page was updated by HotReload
251+ static string? getPathForType(global::System.Type type)
252+ {
253+ var assembly = type.Assembly;
254+ foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes<global::Microsoft.Maui.Controls.Xaml.XamlResourceIdAttribute>(assembly))
255+ {
256+ if (xria.Type == type)
257+ return xria.Path;
258+ }
259+ return null;
260+ }
261+
262+ var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery
263+ {
264+ AssemblyName = typeof(global::Test.TestPage).Assembly.GetName(),
265+ ResourcePath = getPathForType(typeof(global::Test.TestPage)),
266+ Instance = this,
267+ });
268+
269+ if (rlr?.ResourceContent != null)
270+ {
271+ this.InitializeComponentRuntime();
272+ return;
273+ }
274+
275+ var bindingExtension = new global::Microsoft.Maui.Controls.Xaml.BindingExtension();
276+ global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(bindingExtension!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 8, 5);
277+ var __root = this;
278+ global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(__root!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 2, 2);
279+ #if !_MAUIXAML_SG_NAMESCOPE_DISABLE
280+ global::Microsoft.Maui.Controls.Internals.INameScope iNameScope = global::Microsoft.Maui.Controls.Internals.NameScope.GetNameScope(__root) ?? new global::Microsoft.Maui.Controls.Internals.NameScope();
281+ #endif
282+ #if !_MAUIXAML_SG_NAMESCOPE_DISABLE
283+ global::Microsoft.Maui.Controls.Internals.NameScope.SetNameScope(__root, iNameScope);
284+ #endif
285+ #line 8 "{{ testXamlFilePath }} "
286+ bindingExtension.Path = "Product.Size";
287+ #line default
288+ var bindingBase = CreateTypedBindingFrom_bindingExtension(bindingExtension);
289+ if (global::Microsoft.Maui.VisualDiagnostics.GetSourceInfo(bindingBase!) == null)
290+ global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(bindingBase!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 8, 5);
291+ __root.SetBinding(global::Microsoft.Maui.Controls.Page.TitleProperty, bindingBase);
292+ static global::Microsoft.Maui.Controls.BindingBase CreateTypedBindingFrom_bindingExtension(global::Microsoft.Maui.Controls.Xaml.BindingExtension extension)
293+ {
294+ return Create(
295+ getter: static source => source.Product?.Size ?? extension.TargetNullValue as int? ?? default,
296+ extension.Mode,
297+ extension.Converter,
298+ extension.ConverterParameter,
299+ extension.StringFormat,
300+ extension.Source,
301+ extension.FallbackValue,
302+ extension.TargetNullValue);
303+
304+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Maui.Controls.BindingSourceGen, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null", "10.0.0.0")]
305+ static global::Microsoft.Maui.Controls.BindingBase Create(
306+ global::System.Func<global::Test.TestPage, int> getter,
307+ global::Microsoft.Maui.Controls.BindingMode mode = global::Microsoft.Maui.Controls.BindingMode.Default,
308+ global::Microsoft.Maui.Controls.IValueConverter? converter = null,
309+ object? converterParameter = null,
310+ string? stringFormat = null,
311+ object? source = null,
312+ object? fallbackValue = null,
313+ object? targetNullValue = null)
314+ {
315+ global::System.Action<global::Test.TestPage, int>? setter = null;
316+ if (ShouldUseSetter(mode))
317+ {
318+ setter = static (source, value) =>
319+ {
320+ if (source.Product is {} p0)
321+ {
322+ p0.Size = value;
323+ }
324+ };
325+ }
326+
327+ var binding = new global::Microsoft.Maui.Controls.Internals.TypedBinding<global::Test.TestPage, int>(
328+ getter: source => (getter(source), true),
329+ setter,
330+ handlers: new global::System.Tuple<global::System.Func<global::Test.TestPage, object?>, string>[]
331+ {
332+ new(static source => source, "Product"),
333+ new(static source => source.Product, "Size"),
334+ })
335+ {
336+ Mode = mode,
337+ Converter = converter,
338+ ConverterParameter = converterParameter,
339+ StringFormat = stringFormat,
340+ Source = source,
341+ FallbackValue = fallbackValue,
342+ TargetNullValue = targetNullValue
343+ };
344+
345+ return binding;
346+ }
347+
348+
349+ [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
350+ static bool ShouldUseSetter(global::Microsoft.Maui.Controls.BindingMode mode)
351+ => mode == global::Microsoft.Maui.Controls.BindingMode.OneWayToSource
352+ || mode == global::Microsoft.Maui.Controls.BindingMode.TwoWay
353+ || mode == global::Microsoft.Maui.Controls.BindingMode.Default;
354+ }
355+
356+ }
357+ }
358+
184359""" ;
185360
186361 var ( result , generated ) = RunGenerator ( xaml , code ) ;
0 commit comments