diff --git a/src/Controls/src/SourceGen/KnownMarkups.cs b/src/Controls/src/SourceGen/KnownMarkups.cs index b13425c2c1bb..b170a866dbcb 100644 --- a/src/Controls/src/SourceGen/KnownMarkups.cs +++ b/src/Controls/src/SourceGen/KnownMarkups.cs @@ -560,10 +560,11 @@ internal static bool ProvideValueForAppThemeBindingExtension(ElementNode node, I // Get the target property type for type conversion ITypeSymbol? propertyType = null; + IFieldSymbol? bpFieldSymbol = null; if (node.TryGetPropertyName(node.Parent, out XmlName propertyName) && context.Variables.TryGetValue(node.Parent, out ILocalValue parentVar)) { var localName = propertyName.LocalName; - var bpFieldSymbol = parentVar.Type.GetBindableProperty(propertyName.NamespaceURI, ref localName, out bool attached, context, node as IXmlLineInfo); + bpFieldSymbol = parentVar.Type.GetBindableProperty(propertyName.NamespaceURI, ref localName, out bool attached, context, node as IXmlLineInfo); var propertySymbol = parentVar.Type.GetAllProperties(localName, context).FirstOrDefault(); var typeandconverter = bpFieldSymbol?.GetBPTypeAndConverter(context); propertyType = typeandconverter?.type ?? propertySymbol?.Type; @@ -573,6 +574,32 @@ internal static bool ProvideValueForAppThemeBindingExtension(ElementNode node, I if (propertyType is null) propertyType = context.Compilation.ObjectType; + // Helper to get value from node - handles both ValueNode (direct conversion) and ElementNode (via getNodeValue) + string? GetNodeValueString(INode? targetNode) + { + if (targetNode is null) + return null; + + if (targetNode is ValueNode vn) + { + // For ValueNode, convert directly using the property type + if (bpFieldSymbol is not null) + return vn.ConvertTo(bpFieldSymbol, writer, context, context.Variables.TryGetValue(node.Parent, out var pv) ? pv : null); + else if (propertyType is not null) + return vn.ConvertTo(propertyType, writer, context, context.Variables.TryGetValue(node.Parent, out var pv) ? pv : null); + else + return NodeSGExtensions.ValueForLanguagePrimitive(vn.Value as string ?? string.Empty, context.Compilation.ObjectType, context, vn); + } + else if (targetNode is ElementNode) + { + // For ElementNode, use getNodeValue to get the variable reference + var local = getNodeValue(targetNode, propertyType); + return local.ValueAccessor; + } + + return null; + } + // Extract Light, Dark, and Default values from the markup extension string? lightValue = null; string? darkValue = null; @@ -583,24 +610,21 @@ internal static bool ProvideValueForAppThemeBindingExtension(ElementNode node, I || node.Properties.TryGetValue(new XmlName(null, "Default"), out defaultNode) || (node.CollectionItems.Count == 1 && (defaultNode = node.CollectionItems[0]) != null)) { - var defaultLocal = getNodeValue(defaultNode, propertyType); - defaultValue = defaultLocal.ValueAccessor; + defaultValue = GetNodeValueString(defaultNode); } // Check for Light property if (node.Properties.TryGetValue(new XmlName("", "Light"), out INode? lightNode) || node.Properties.TryGetValue(new XmlName(null, "Light"), out lightNode)) { - var lightLocal = getNodeValue(lightNode, propertyType); - lightValue = lightLocal.ValueAccessor; + lightValue = GetNodeValueString(lightNode); } // Check for Dark property if (node.Properties.TryGetValue(new XmlName("", "Dark"), out INode? darkNode) || node.Properties.TryGetValue(new XmlName(null, "Dark"), out darkNode)) { - var darkLocal = getNodeValue(darkNode, propertyType); - darkValue = darkLocal.ValueAccessor; + darkValue = GetNodeValueString(darkNode); } // At least one value must be set @@ -649,14 +673,6 @@ internal static bool ProvideValueForStaticResourceExtension(ElementNode node, In } var resource = GetResourceNode(eNode, context, (string)keyValueNode.Value); - if (resource != null && getNodeValue != null) - { - var lvalue = getNodeValue(resource, context.Compilation.ObjectType); - value = lvalue.ValueAccessor; - returnType = lvalue.Type; - return true; - } - if (resource is null || !context.Variables.TryGetValue(resource, out var variable)) { returnType = context.Compilation.ObjectType; @@ -664,7 +680,6 @@ internal static bool ProvideValueForStaticResourceExtension(ElementNode node, In return false; } - //if the resource is a string, try to convert it if (resource.CollectionItems.Count == 1 && resource.CollectionItems[0] is ValueNode vn && vn.Value is string) { @@ -676,6 +691,14 @@ internal static bool ProvideValueForStaticResourceExtension(ElementNode node, In var typeandconverter = bpFieldSymbol?.GetBPTypeAndConverter(context); var propertyType = typeandconverter?.type ?? propertySymbol?.Type; + var converter = typeandconverter?.converter; + + // If no converter from BP, check the property's TypeConverter attribute + if (converter == null && propertySymbol != null) + { + List attributes = [.. propertySymbol.GetAttributes(), .. propertyType!.GetAttributes()]; + converter = attributes.FirstOrDefault(ad => ad.AttributeClass?.ToString() == "System.ComponentModel.TypeConverterAttribute")?.ConstructorArguments[0].Value as ITypeSymbol; + } if (propertyType!.Equals(context.Compilation.GetSpecialType(SpecialType.System_String), SymbolEqualityComparer.Default)) { @@ -685,7 +708,7 @@ internal static bool ProvideValueForStaticResourceExtension(ElementNode node, In } try { - value = vn.ConvertTo(propertyType!, typeandconverter?.converter, writer, context, parentVar); + value = vn.ConvertTo(propertyType!, converter, writer, context, parentVar); } catch (Exception) { @@ -698,6 +721,15 @@ internal static bool ProvideValueForStaticResourceExtension(ElementNode node, In return true; } } + + // If we get here and getNodeValue is provided, use it as fallback + if (getNodeValue != null) + { + var lvalue = getNodeValue(resource, context.Compilation.ObjectType); + value = lvalue.ValueAccessor; + returnType = lvalue.Type; + return true; + } //Fallback to runtime resolution of StaticResource returnType = context.Compilation.ObjectType; diff --git a/src/Controls/src/SourceGen/NodeSGExtensions.cs b/src/Controls/src/SourceGen/NodeSGExtensions.cs index 3621e973c188..303aa0506a3d 100644 --- a/src/Controls/src/SourceGen/NodeSGExtensions.cs +++ b/src/Controls/src/SourceGen/NodeSGExtensions.cs @@ -497,6 +497,9 @@ public static void ProvideValue(this ElementNode node, IndentedTextWriter writer } public static bool TryProvideValue(this ElementNode node, IndentedTextWriter writer, SourceGenContext context) + => TryProvideValue(node, writer, context, null); + + public static bool TryProvideValue(this ElementNode node, IndentedTextWriter writer, SourceGenContext context, GetNodeValueDelegate? getNodeValue) { if (!context.Variables.TryGetValue(node, out var variable)) return false; @@ -505,7 +508,7 @@ public static bool TryProvideValue(this ElementNode node, IndentedTextWriter wri return false; if (GetKnownLateMarkupExtensions(context).TryGetValue(variable.Type, out var provideValue) - && provideValue.Invoke(node, writer, context, null, out var returnType0, out var value)) + && provideValue.Invoke(node, writer, context, getNodeValue, out var returnType0, out var value)) { var variableName = NamingHelpers.CreateUniqueVariableName(context, returnType0 ?? context.Compilation.ObjectType); context.Writer.WriteLine($"var {variableName} = {value};"); @@ -516,7 +519,7 @@ public static bool TryProvideValue(this ElementNode node, IndentedTextWriter wri } if (GetKnownValueProviders(context).TryGetValue(variable.Type, out provideValue) - && provideValue.Invoke(node, writer, context, null, out returnType0, out value)) + && provideValue.Invoke(node, writer, context, getNodeValue, out returnType0, out value)) { var variableName = NamingHelpers.CreateUniqueVariableName(context, returnType0 ?? context.Compilation.ObjectType); context.Writer.WriteLine($"var {variableName} = {value};"); diff --git a/src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs b/src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs index 9d425cd4cc3e..a933c0cf13f7 100644 --- a/src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs +++ b/src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs @@ -120,7 +120,7 @@ public void Visit(ElementNode node, INode parentNode) } //IMarkupExtension or IValueProvider => ProvideValue() - node.TryProvideValue(Writer, context); + node.TryProvideValue(Writer, context, getNodeValue); if (propertyName != XmlName.Empty) { diff --git a/src/Controls/tests/SourceGen.UnitTests/InitializeComponent/AppThemeBinding.cs b/src/Controls/tests/SourceGen.UnitTests/InitializeComponent/AppThemeBinding.cs new file mode 100644 index 000000000000..945a67e73d20 --- /dev/null +++ b/src/Controls/tests/SourceGen.UnitTests/InitializeComponent/AppThemeBinding.cs @@ -0,0 +1,327 @@ +using System; +using System.IO; +using System.Linq; +using Xunit; + +namespace Microsoft.Maui.Controls.SourceGen.UnitTests; + +public class AppThemeBinding : SourceGenXamlInitializeComponentTestBase +{ + [Fact] + public void AppThemeBindingWithLightAndDark() + { + var xaml = +""" + + +"""; + + var code = +""" +using System; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Xaml; + +namespace Test; + +[XamlProcessing(XamlInflator.SourceGen)] +public partial class TestPage : ContentPage +{ + public TestPage() + { + InitializeComponent(); + } +} +"""; + + var testXamlFilePath = Path.Combine(Environment.CurrentDirectory, "Test.xaml"); + var expected = $$""" +//------------------------------------------------------------------------------ +// +// This code was generated by a .NET MAUI source generator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ +#nullable enable + +namespace Test; + +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Maui.Controls.SourceGen, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null", "10.0.0.0")] +public partial class TestPage +{ + private partial void InitializeComponent() + { + // Fallback to Runtime inflation if the page was updated by HotReload + static string? getPathForType(global::System.Type type) + { + var assembly = type.Assembly; + foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes(assembly)) + { + if (xria.Type == type) + return xria.Path; + } + return null; + } + + var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery + { + AssemblyName = typeof(global::Test.TestPage).Assembly.GetName(), + ResourcePath = getPathForType(typeof(global::Test.TestPage)), + Instance = this, + }); + + if (rlr?.ResourceContent != null) + { + this.InitializeComponentRuntime(); + return; + } + + var appThemeBindingExtension = new global::Microsoft.Maui.Controls.Xaml.AppThemeBindingExtension(); + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(appThemeBindingExtension!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 6, 2); + var __root = this; + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(__root!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 2, 2); +#if !_MAUIXAML_SG_NAMESCOPE_DISABLE + global::Microsoft.Maui.Controls.Internals.INameScope iNameScope = global::Microsoft.Maui.Controls.Internals.NameScope.GetNameScope(__root) ?? new global::Microsoft.Maui.Controls.Internals.NameScope(); +#endif +#if !_MAUIXAML_SG_NAMESCOPE_DISABLE + global::Microsoft.Maui.Controls.Internals.NameScope.SetNameScope(__root, iNameScope); +#endif +#line 6 "{{testXamlFilePath}}" + appThemeBindingExtension.Light = "White"; +#line default +#line 6 "{{testXamlFilePath}}" + appThemeBindingExtension.Dark = "Black"; +#line default + var appThemeBinding = new global::Microsoft.Maui.Controls.AppThemeBinding { Light = global::Microsoft.Maui.Graphics.Colors.White, Dark = global::Microsoft.Maui.Graphics.Colors.Black }; + if (global::Microsoft.Maui.VisualDiagnostics.GetSourceInfo(appThemeBinding!) == null) + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(appThemeBinding!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 6, 2); + __root.SetBinding(global::Microsoft.Maui.Controls.VisualElement.BackgroundColorProperty, appThemeBinding); + } +} + +"""; + + var (result, generated) = RunGenerator(xaml, code); + Assert.False(result.Diagnostics.Any()); + Assert.Equal(expected, generated, ignoreLineEndingDifferences: true); + } + + [Fact] + public void AppThemeBindingWithDefault() + { + var xaml = +""" + + +"""; + + var code = +""" +using System; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Xaml; + +namespace Test; + +[XamlProcessing(XamlInflator.SourceGen)] +public partial class TestPage : ContentPage +{ + public TestPage() + { + InitializeComponent(); + } +} +"""; + + var testXamlFilePath = Path.Combine(Environment.CurrentDirectory, "Test.xaml"); + var expected = $$""" +//------------------------------------------------------------------------------ +// +// This code was generated by a .NET MAUI source generator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ +#nullable enable + +namespace Test; + +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Maui.Controls.SourceGen, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null", "10.0.0.0")] +public partial class TestPage +{ + private partial void InitializeComponent() + { + // Fallback to Runtime inflation if the page was updated by HotReload + static string? getPathForType(global::System.Type type) + { + var assembly = type.Assembly; + foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes(assembly)) + { + if (xria.Type == type) + return xria.Path; + } + return null; + } + + var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery + { + AssemblyName = typeof(global::Test.TestPage).Assembly.GetName(), + ResourcePath = getPathForType(typeof(global::Test.TestPage)), + Instance = this, + }); + + if (rlr?.ResourceContent != null) + { + this.InitializeComponentRuntime(); + return; + } + + var appThemeBindingExtension = new global::Microsoft.Maui.Controls.Xaml.AppThemeBindingExtension(); + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(appThemeBindingExtension!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 6, 2); + var __root = this; + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(__root!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 2, 2); +#if !_MAUIXAML_SG_NAMESCOPE_DISABLE + global::Microsoft.Maui.Controls.Internals.INameScope iNameScope = global::Microsoft.Maui.Controls.Internals.NameScope.GetNameScope(__root) ?? new global::Microsoft.Maui.Controls.Internals.NameScope(); +#endif +#if !_MAUIXAML_SG_NAMESCOPE_DISABLE + global::Microsoft.Maui.Controls.Internals.NameScope.SetNameScope(__root, iNameScope); +#endif +#line 6 "{{testXamlFilePath}}" + appThemeBindingExtension.Default = "Gray"; +#line default +#line 6 "{{testXamlFilePath}}" + appThemeBindingExtension.Dark = "Black"; +#line default + var appThemeBinding = new global::Microsoft.Maui.Controls.AppThemeBinding { Dark = global::Microsoft.Maui.Graphics.Colors.Black, Default = global::Microsoft.Maui.Graphics.Colors.Gray }; + if (global::Microsoft.Maui.VisualDiagnostics.GetSourceInfo(appThemeBinding!) == null) + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(appThemeBinding!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 6, 2); + __root.SetBinding(global::Microsoft.Maui.Controls.VisualElement.BackgroundColorProperty, appThemeBinding); + } +} + +"""; + + var (result, generated) = RunGenerator(xaml, code); + Assert.False(result.Diagnostics.Any()); + Assert.Equal(expected, generated, ignoreLineEndingDifferences: true); + } + + [Fact] + public void AppThemeBindingWithAllThree() + { + var xaml = +""" + + +"""; + + var code = +""" +using System; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Xaml; + +namespace Test; + +[XamlProcessing(XamlInflator.SourceGen)] +public partial class TestPage : ContentPage +{ + public TestPage() + { + InitializeComponent(); + } +} +"""; + + var testXamlFilePath = Path.Combine(Environment.CurrentDirectory, "Test.xaml"); + var expected = $$""" +//------------------------------------------------------------------------------ +// +// This code was generated by a .NET MAUI source generator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ +#nullable enable + +namespace Test; + +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Maui.Controls.SourceGen, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null", "10.0.0.0")] +public partial class TestPage +{ + private partial void InitializeComponent() + { + // Fallback to Runtime inflation if the page was updated by HotReload + static string? getPathForType(global::System.Type type) + { + var assembly = type.Assembly; + foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes(assembly)) + { + if (xria.Type == type) + return xria.Path; + } + return null; + } + + var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery + { + AssemblyName = typeof(global::Test.TestPage).Assembly.GetName(), + ResourcePath = getPathForType(typeof(global::Test.TestPage)), + Instance = this, + }); + + if (rlr?.ResourceContent != null) + { + this.InitializeComponentRuntime(); + return; + } + + var appThemeBindingExtension = new global::Microsoft.Maui.Controls.Xaml.AppThemeBindingExtension(); + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(appThemeBindingExtension!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 6, 2); + var __root = this; + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(__root!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 2, 2); +#if !_MAUIXAML_SG_NAMESCOPE_DISABLE + global::Microsoft.Maui.Controls.Internals.INameScope iNameScope = global::Microsoft.Maui.Controls.Internals.NameScope.GetNameScope(__root) ?? new global::Microsoft.Maui.Controls.Internals.NameScope(); +#endif +#if !_MAUIXAML_SG_NAMESCOPE_DISABLE + global::Microsoft.Maui.Controls.Internals.NameScope.SetNameScope(__root, iNameScope); +#endif +#line 6 "{{testXamlFilePath}}" + appThemeBindingExtension.Light = "White"; +#line default +#line 6 "{{testXamlFilePath}}" + appThemeBindingExtension.Dark = "Black"; +#line default +#line 6 "{{testXamlFilePath}}" + appThemeBindingExtension.Default = "Gray"; +#line default + var appThemeBinding = new global::Microsoft.Maui.Controls.AppThemeBinding { Light = global::Microsoft.Maui.Graphics.Colors.White, Dark = global::Microsoft.Maui.Graphics.Colors.Black, Default = global::Microsoft.Maui.Graphics.Colors.Gray }; + if (global::Microsoft.Maui.VisualDiagnostics.GetSourceInfo(appThemeBinding!) == null) + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(appThemeBinding!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 6, 2); + __root.SetBinding(global::Microsoft.Maui.Controls.VisualElement.BackgroundColorProperty, appThemeBinding); + } +} + +"""; + + var (result, generated) = RunGenerator(xaml, code); + Assert.False(result.Diagnostics.Any()); + Assert.Equal(expected, generated, ignoreLineEndingDifferences: true); + } +} diff --git a/src/Controls/tests/SourceGen.UnitTests/InitializeComponent/StaticResourceWithTypeConversion.cs b/src/Controls/tests/SourceGen.UnitTests/InitializeComponent/StaticResourceWithTypeConversion.cs new file mode 100644 index 000000000000..b460c1a4a8e2 --- /dev/null +++ b/src/Controls/tests/SourceGen.UnitTests/InitializeComponent/StaticResourceWithTypeConversion.cs @@ -0,0 +1,128 @@ +using System; +using System.IO; +using System.Linq; +using Xunit; + +namespace Microsoft.Maui.Controls.SourceGen.UnitTests; + +public class StaticResourceWithTypeConversion : SourceGenXamlInitializeComponentTestBase +{ + [Fact] + public void StaticResourceForGridRowAndColumnDefinitions() + { + var xaml = +""" + + + + 10, *, *, auto + + + +"""; + + var code = +""" +using System; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Xaml; + +namespace Test; + +[XamlProcessing(XamlInflator.SourceGen)] +public partial class TestPage : ContentPage +{ + public TestPage() + { + InitializeComponent(); + } +} +"""; + +var expected = +""" +//------------------------------------------------------------------------------ +// +// This code was generated by a .NET MAUI source generator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ +#nullable enable + +namespace Test; + +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Maui.Controls.SourceGen, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null", "10.0.0.0")] +public partial class TestPage +{ + private partial void InitializeComponent() + { + // Fallback to Runtime inflation if the page was updated by HotReload + static string? getPathForType(global::System.Type type) + { + var assembly = type.Assembly; + foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes(assembly)) + { + if (xria.Type == type) + return xria.Path; + } + return null; + } + + var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery + { + AssemblyName = typeof(global::Test.TestPage).Assembly.GetName(), + ResourcePath = getPathForType(typeof(global::Test.TestPage)), + Instance = this, + }); + + if (rlr?.ResourceContent != null) + { + this.InitializeComponentRuntime(); + return; + } + + string string0 = "10, *, *, auto"; + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(string0!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 6, 10); + var staticResourceExtension = new global::Microsoft.Maui.Controls.Xaml.StaticResourceExtension(); + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(staticResourceExtension!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 8, 8); + var grid = new global::Microsoft.Maui.Controls.Grid(); + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(grid!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 8, 3); + var __root = this; + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(__root!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 2, 2); +#if !_MAUIXAML_SG_NAMESCOPE_DISABLE + global::Microsoft.Maui.Controls.Internals.INameScope iNameScope = global::Microsoft.Maui.Controls.Internals.NameScope.GetNameScope(__root) ?? new global::Microsoft.Maui.Controls.Internals.NameScope(); +#endif +#if !_MAUIXAML_SG_NAMESCOPE_DISABLE + global::Microsoft.Maui.Controls.Internals.NameScope.SetNameScope(__root, iNameScope); +#endif +#if !_MAUIXAML_SG_NAMESCOPE_DISABLE + grid.transientNamescope = iNameScope; +#endif + __root.Resources["GridRowDef"] = string0; +#line 8 "/Users/sde/Projects/Microsoft/maui/artifacts/bin/SourceGen.UnitTests/Debug/net10.0/Test.xaml" + staticResourceExtension.Key = "GridRowDef"; +#line default + var rowDefinitionCollection = new global::Microsoft.Maui.Controls.RowDefinitionCollection([new RowDefinition(new global::Microsoft.Maui.GridLength(10, global::Microsoft.Maui.GridUnitType.Absolute)), new RowDefinition(global::Microsoft.Maui.GridLength.Star), new RowDefinition(global::Microsoft.Maui.GridLength.Star), new RowDefinition(global::Microsoft.Maui.GridLength.Auto)]); + if (global::Microsoft.Maui.VisualDiagnostics.GetSourceInfo(rowDefinitionCollection!) == null) + global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(rowDefinitionCollection!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 8, 8); +#line 8 "/Users/sde/Projects/Microsoft/maui/artifacts/bin/SourceGen.UnitTests/Debug/net10.0/Test.xaml" + grid.SetValue(global::Microsoft.Maui.Controls.Grid.RowDefinitionsProperty, rowDefinitionCollection); +#line default +#line 8 "/Users/sde/Projects/Microsoft/maui/artifacts/bin/SourceGen.UnitTests/Debug/net10.0/Test.xaml" + __root.SetValue(global::Microsoft.Maui.Controls.ContentPage.ContentProperty, grid); +#line default + } +} + +"""; + + var (result, generated) = RunGenerator(xaml, code); + + Assert.Empty(result.Diagnostics); + Assert.Equal(expected, generated, ignoreLineEndingDifferences: true); + } +}