diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Given_HotReloadEnabledInBuild.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Given_HotReloadEnabledInBuild.cs
index 8694075a0a51..a8519c1b422c 100644
--- a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Given_HotReloadEnabledInBuild.cs
+++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Given_HotReloadEnabledInBuild.cs
@@ -332,4 +332,61 @@ public MainPage()
await test.RunAsync();
}
+
+ [TestMethod]
+ public async Task SetOriginalSourceLocationIncludedInOutputForEmptyDataTemplates()
+ {
+ var xamlFile = new XamlFile("EmptyDataTemplatePage.xaml",
+ """
+
+
+
+
+
+
+
+
+
+
+
+ """);
+ var configOverride = new Dictionary { { "build_property.UnoForceHotReloadCodeGen", "true" } };
+ var test = new Verify.Test(xamlFile)
+ {
+ TestState =
+ {
+ Sources =
+ {
+ """
+ using Microsoft.UI.Xaml;
+ using Microsoft.UI.Xaml.Controls;
+ namespace TestRepro
+ {
+ public sealed partial class EmptyDataTemplatePage : Page
+ {
+ public EmptyDataTemplatePage()
+ {
+ this.InitializeComponent();
+ }
+ }
+ }
+ """
+ }
+ },
+ ReferenceAssemblies = _Dotnet.Current.WithUnoPackage(),
+ GlobalConfigOverride = configOverride,
+ }.AddGeneratedSources();
+
+ await test.RunAsync();
+ }
}
diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706.cs
new file mode 100644
index 000000000000..98e8134c5d82
--- /dev/null
+++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706.cs
@@ -0,0 +1,240 @@
+//
+#pragma warning disable CS0114
+#pragma warning disable CS0108
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using Uno.UI;
+using Uno.UI.Xaml;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Documents;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Media.Animation;
+using Microsoft.UI.Xaml.Shapes;
+using Windows.UI.Text;
+using Uno.Extensions;
+using Uno;
+using Uno.UI.Helpers;
+using Uno.UI.Helpers.Xaml;
+using MyProject;
+
+#if __ANDROID__
+using _View = Android.Views.View;
+#elif __IOS__
+using _View = UIKit.UIView;
+#elif __MACOS__
+using _View = AppKit.NSView;
+#else
+using _View = Microsoft.UI.Xaml.UIElement;
+#endif
+
+namespace TestRepro
+{
+ partial class EmptyDataTemplatePage : global::Microsoft.UI.Xaml.Controls.Page
+ {
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ private const string __baseUri_prefix_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706 = "ms-appx:///TestProject/";
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ private const string __baseUri_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706 = "ms-appx:///TestProject/";
+ private global::Microsoft.UI.Xaml.NameScope __nameScope = new global::Microsoft.UI.Xaml.NameScope();
+ private void InitializeComponent()
+ {
+ NameScope.SetNameScope(this, __nameScope);
+ var __that = this;
+ base.IsParsing = true;
+ Resources[
+ "MyEmptyTemplate"
+ ] =
+ new global::Uno.UI.Xaml.WeakResourceInitializer(this, __ResourceOwner_1 =>
+ {
+ return
+ new global::Microsoft.UI.Xaml.DataTemplate( ) .GenericApply(__that, __nameScope, (ApplyMethod_0 ))
+ ;
+ }
+ )
+ ;
+ // Source 0\EmptyDataTemplatePage.xaml (Line 1:3)
+ base.Content =
+ new global::Microsoft.UI.Xaml.Controls.StackPanel
+ {
+ IsParsing = true,
+ // Source 0\EmptyDataTemplatePage.xaml (Line 11:3)
+ Children =
+ {
+ new global::Microsoft.UI.Xaml.Controls.ListView
+ {
+ IsParsing = true,
+ // Source 0\EmptyDataTemplatePage.xaml (Line 12:4)
+ }
+ .GenericApply(__that, __nameScope, (ApplyMethod_1 ))
+ ,
+ new global::Microsoft.UI.Xaml.Controls.Button
+ {
+ IsParsing = true,
+ Name = "ButtonWithEmptyDataTemplate",
+ ContentTemplate = new global::Microsoft.UI.Xaml.DataTemplate( ) .GenericApply(__that, __nameScope, (ApplyMethod_2 ))
+ ,
+ // Source 0\EmptyDataTemplatePage.xaml (Line 13:4)
+ }
+ .GenericApply(__that, __nameScope, (ApplyMethod_3 ))
+ ,
+ }
+ }
+ .GenericApply(__that, __nameScope, (ApplyMethod_4 ))
+ ;
+
+ this
+ .GenericApply(__that, __nameScope, (ApplyMethod_5 ))
+ .GenericApply(__that, __nameScope, (ApplyMethod_6 ))
+ ;
+ OnInitializeCompleted();
+
+ Bindings = new EmptyDataTemplatePage_Bindings(this);
+ ((global::Microsoft.UI.Xaml.FrameworkElement)this).Loading += __UpdateBindingsAndResources;
+ }
+ partial void OnInitializeCompleted();
+ private void __UpdateBindingsAndResources(global::Microsoft.UI.Xaml.FrameworkElement s, object e)
+ {
+ this.Bindings.UpdateResources();
+ }
+ private void ApplyMethod_0(global::System.Object __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope)
+ {
+ global::Uno.UI.Helpers.MarkupHelper.SetElementProperty(__p1, "OriginalSourceLocation", "file:///C:/Project/0/EmptyDataTemplatePage.xaml#L7:4");
+ }
+
+ private void ApplyMethod_1(global::Microsoft.UI.Xaml.Controls.ListView __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope)
+ {
+ /* _isTopLevelDictionary:False */
+ __that._component_0 = __p1;
+ global::Uno.UI.ResourceResolverSingleton.Instance.ApplyResource(__p1, global::Microsoft.UI.Xaml.Controls.ListView.ItemTemplateProperty, "MyItemTemplate", isThemeResourceExtension: false, isHotReloadSupported: true, context: global::MyProject.GlobalStaticResources.__ParseContext_);
+ global::Uno.UI.FrameworkElementHelper.SetBaseUri(__p1, __baseUri_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706, "file:///C:/Project/0/EmptyDataTemplatePage.xaml", 12, 4);
+ __p1.CreationComplete();
+ }
+
+ private void ApplyMethod_2(global::System.Object __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope)
+ {
+ global::Uno.UI.Helpers.MarkupHelper.SetElementProperty(__p1, "OriginalSourceLocation", "file:///C:/Project/0/EmptyDataTemplatePage.xaml#L15:6");
+ }
+
+ private void ApplyMethod_3(global::Microsoft.UI.Xaml.Controls.Button __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope)
+ {
+ __nameScope.RegisterName("ButtonWithEmptyDataTemplate", __p1);
+ __that.ButtonWithEmptyDataTemplate = __p1;
+ global::Uno.UI.FrameworkElementHelper.SetBaseUri(__p1, __baseUri_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706, "file:///C:/Project/0/EmptyDataTemplatePage.xaml", 13, 4);
+ __p1.CreationComplete();
+ }
+
+ private void ApplyMethod_4(global::Microsoft.UI.Xaml.Controls.StackPanel __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope)
+ {
+ global::Uno.UI.FrameworkElementHelper.SetBaseUri(__p1, __baseUri_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706, "file:///C:/Project/0/EmptyDataTemplatePage.xaml", 11, 3);
+ __p1.CreationComplete();
+ }
+
+ private void ApplyMethod_5(global::Microsoft.UI.Xaml.Controls.Page __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope)
+ {
+ // Source 0\EmptyDataTemplatePage.xaml (Line 1:3)
+
+ // WARNING Property __p1.base does not exist on {http://schemas.microsoft.com/winfx/2006/xaml/presentation}Page, the namespace is http://www.w3.org/XML/1998/namespace. This error was considered irrelevant by the XamlFileGenerator
+ }
+
+ private void ApplyMethod_6(global::Microsoft.UI.Xaml.Controls.Page __p1, EmptyDataTemplatePage __that, global::Microsoft.UI.Xaml.NameScope __nameScope)
+ {
+ /* _isTopLevelDictionary:False */
+ __that._component_1 = __p1;
+ // Class TestRepro.EmptyDataTemplatePage
+ global::Uno.UI.ResourceResolverSingleton.Instance.ApplyResource(__p1, global::Microsoft.UI.Xaml.Controls.Page.BackgroundProperty, "ApplicationPageBackgroundThemeBrush", isThemeResourceExtension: true, isHotReloadSupported: true, context: global::MyProject.GlobalStaticResources.__ParseContext_);
+ global::Uno.UI.FrameworkElementHelper.SetBaseUri(__p1, __baseUri_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706, "file:///C:/Project/0/EmptyDataTemplatePage.xaml", 1, 3);
+ __p1.CreationComplete();
+ }
+
+ private global::Microsoft.UI.Xaml.Data.ElementNameSubject _ButtonWithEmptyDataTemplateSubject { get; set; } = new global::Microsoft.UI.Xaml.Data.ElementNameSubject();
+ private global::Microsoft.UI.Xaml.Controls.Button ButtonWithEmptyDataTemplate
+ {
+ get
+ {
+ return (global::Microsoft.UI.Xaml.Controls.Button)_ButtonWithEmptyDataTemplateSubject.ElementInstance;
+ }
+ set
+ {
+ _ButtonWithEmptyDataTemplateSubject.ElementInstance = value;
+ }
+ }
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ [global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate]
+ private class __EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706_TestReproEmptyDataTemplatePage
+ {
+ }
+ private global::Microsoft.UI.Xaml.Markup.ComponentHolder _component_0_Holder { get; } = new global::Microsoft.UI.Xaml.Markup.ComponentHolder(isWeak: true);
+ private global::Microsoft.UI.Xaml.Controls.ListView _component_0
+ {
+ get
+ {
+ return (global::Microsoft.UI.Xaml.Controls.ListView)_component_0_Holder.Instance;
+ }
+ set
+ {
+ _component_0_Holder.Instance = value;
+ }
+ }
+ private global::Microsoft.UI.Xaml.Markup.ComponentHolder _component_1_Holder { get; } = new global::Microsoft.UI.Xaml.Markup.ComponentHolder(isWeak: true);
+ private global::Microsoft.UI.Xaml.Controls.Page _component_1
+ {
+ get
+ {
+ return (global::Microsoft.UI.Xaml.Controls.Page)_component_1_Holder.Instance;
+ }
+ set
+ {
+ _component_1_Holder.Instance = value;
+ }
+ }
+ private interface IEmptyDataTemplatePage_Bindings
+ {
+ void Initialize();
+ void Update();
+ void UpdateResources();
+ void StopTracking();
+ void NotifyXLoad(string name);
+ }
+ #pragma warning disable 0169 // Suppress unused field warning in case Bindings is not used.
+ private IEmptyDataTemplatePage_Bindings Bindings;
+ #pragma warning restore 0169
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ private class EmptyDataTemplatePage_Bindings : IEmptyDataTemplatePage_Bindings
+ {
+ #if UNO_HAS_UIELEMENT_IMPLICIT_PINNING
+ private global::System.WeakReference _ownerReference;
+ private global::TestRepro.EmptyDataTemplatePage Owner { get => (global::TestRepro.EmptyDataTemplatePage)_ownerReference?.Target; set => _ownerReference = new global::System.WeakReference(value); }
+ #else
+ private global::TestRepro.EmptyDataTemplatePage Owner { get; set; }
+ #endif
+ public EmptyDataTemplatePage_Bindings(global::TestRepro.EmptyDataTemplatePage owner)
+ {
+ Owner = owner;
+ }
+ void IEmptyDataTemplatePage_Bindings.NotifyXLoad(string name)
+ {
+ }
+ void IEmptyDataTemplatePage_Bindings.Initialize()
+ {
+ }
+ void IEmptyDataTemplatePage_Bindings.Update()
+ {
+ var owner = Owner;
+ }
+ void IEmptyDataTemplatePage_Bindings.UpdateResources()
+ {
+ var owner = Owner;
+ owner._component_0.UpdateResourceBindings();
+ owner._component_1.UpdateResourceBindings();
+ }
+ void IEmptyDataTemplatePage_Bindings.StopTracking()
+ {
+ }
+ }
+ }
+}
diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_GlobalStaticResources.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_GlobalStaticResources.cs
new file mode 100644
index 000000000000..d4de7cabbd66
--- /dev/null
+++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_GlobalStaticResources.cs
@@ -0,0 +1,59 @@
+//
+namespace MyProject
+{
+ ///
+ /// Contains all the static resources defined for the application
+ ///
+ [global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdate]
+ public sealed partial class GlobalStaticResources
+ {
+ static bool _initialized;
+ private static bool _stylesRegistered;
+ private static bool _dictionariesRegistered;
+ internal static global::Uno.UI.Xaml.XamlParseContext __ParseContext_ { get; } = new global::Uno.UI.Xaml.XamlParseContext()
+ {
+ AssemblyName = "TestProject",
+ }
+ ;
+
+ static GlobalStaticResources()
+ {
+ Initialize();
+ }
+ public static void Initialize()
+ {
+ if (!_initialized)
+ {
+ _initialized = true;
+ global::Uno.UI.Toolkit.GlobalStaticResources.Initialize();
+ global::Uno.UI.GlobalStaticResources.Initialize();
+ global::Uno.UI.Toolkit.GlobalStaticResources.RegisterDefaultStyles();
+ global::Uno.UI.GlobalStaticResources.RegisterDefaultStyles();
+ global::Uno.UI.Toolkit.GlobalStaticResources.RegisterResourceDictionariesBySource();
+ global::Uno.UI.GlobalStaticResources.RegisterResourceDictionariesBySource();
+ }
+ }
+ public static void RegisterDefaultStyles()
+ {
+ if(!_stylesRegistered)
+ {
+ _stylesRegistered = true;
+ RegisterDefaultStyles_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706();
+ }
+ }
+ // Register ResourceDictionaries using ms-appx:/// syntax, this is called for external resources
+ public static void RegisterResourceDictionariesBySource()
+ {
+ if(!_dictionariesRegistered)
+ {
+ _dictionariesRegistered = true;
+ }
+ }
+ // Register ResourceDictionaries using ms-resource:/// syntax, this is called for local resources
+ internal static void RegisterResourceDictionariesBySourceLocal()
+ {
+ }
+ static partial void RegisterDefaultStyles_EmptyDataTemplatePage_0f836ad6c048ef5ac0e673406e3c3706();
+
+ }
+}
diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_LocalizationResources.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_LocalizationResources.cs
new file mode 100644
index 000000000000..115ce87c0105
--- /dev/null
+++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/SOSLIIOFEDT/XamlCodeGenerator_LocalizationResources.cs
@@ -0,0 +1,2 @@
+//
+[assembly: global::System.Reflection.AssemblyMetadata("UnoHasLocalizationResources", "False")]
\ No newline at end of file
diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Verifiers/CSGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Verifiers/CSGenerator.cs
index 383632841446..79fe7ee82300 100644
--- a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Verifiers/CSGenerator.cs
+++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Verifiers/CSGenerator.cs
@@ -1,8 +1,6 @@
-#if DEBUG
-// Uncomment the following line to write expected files to disk
+// Uncomment the following line to write expected files to disk
// Don't commit this line uncommented.
// #define WRITE_EXPECTED
-#endif
using System.Collections.Immutable;
using System.Diagnostics;
@@ -16,6 +14,11 @@
using Uno.UI.SourceGenerators.MetadataUpdates;
using Uno.UI.SourceGenerators.XamlGenerator;
+#if !DEBUG && WRITE_EXPECTED
+#error Cannot commit with #define WRITE_EXPECTED
+#endif
+
+
namespace Uno.UI.SourceGenerators.Tests.Verifiers
{
public record struct XamlFile(string FileName, string Contents);
diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs
index 924580d3323b..33f957f64a72 100644
--- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs
+++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs
@@ -5996,28 +5996,28 @@ private void BuildChild(IIndentedStringBuilder writer, XamlMemberDefinition? own
var contentOwner = xamlObjectDefinition.Members.FirstOrDefault(m => m.Member.Name == "_UnknownContent");
var contentLocation = (IXamlLocation)xamlObjectDefinition.Members.FirstOrDefault(m => m.Member.Name == "Key") ?? xamlObjectDefinition;
- if (contentOwner != null)
+ if (contentOwner is not null || _isHotReloadEnabled) // If Hot Reload is enabled, we still need to attach the source location, even on empty elements
{
- var resourceOwner = CurrentResourceOwnerName;
-
+ if (contentOwner is not null)
+ {
+ var resourceOwner = CurrentResourceOwnerName;
#if USE_NEW_TP_CODEGEN
- writer.Append($"{resourceOwner}, (__owner, __settings) => ");
+ writer.Append($"{resourceOwner}, (__owner, __settings) => ");
#else
- writer.Append($"{resourceOwner}, (__owner) => ");
+ writer.Append($"{resourceOwner}, (__owner) => ");
#endif
-
- // This case is to support the layout switching for the ListViewBaseLayout, which is not
- // a FrameworkTemplate. This will need to be removed when this custom list view is removed.
- var returnType = typeName == "ListViewBaseLayoutTemplate" ? "global::Uno.UI.Controls.Legacy.ListViewBaseLayout" : "_View";
- BuildChildThroughSubclass(writer, contentOwner, returnType);
+ // This case is to support the layout switching for the ListViewBaseLayout, which is not
+ // a FrameworkTemplate. This will need to be removed when this custom list view is removed.
+ var returnType = typeName == "ListViewBaseLayoutTemplate" ? "global::Uno.UI.Controls.Legacy.ListViewBaseLayout" : "_View";
+ BuildChildThroughSubclass(writer, contentOwner, returnType);
+ }
writer.AppendIndented(")");
+
if (_isHotReloadEnabled)
{
- using (var applyWriter = CreateApplyBlock(writer, null, out var closureName))
- {
- TrySetOriginalSourceLocation(applyWriter, closureName, contentLocation.LineNumber, contentLocation.LinePosition);
- }
+ using var applyWriter = CreateApplyBlock(writer, null, out var closureName);
+ TrySetOriginalSourceLocation(applyWriter, closureName, contentLocation.LineNumber, contentLocation.LinePosition);
}
}