diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/TPXBRXLE/XamlCodeGenerator_MainPage_d6cd66944958ced0c513e0a04797b51d.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/TPXBRXLE/XamlCodeGenerator_MainPage_d6cd66944958ced0c513e0a04797b51d.cs index ddf44f17bc52..1240075ea24b 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/TPXBRXLE/XamlCodeGenerator_MainPage_d6cd66944958ced0c513e0a04797b51d.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/TPXBRXLE/XamlCodeGenerator_MainPage_d6cd66944958ced0c513e0a04797b51d.cs @@ -108,6 +108,10 @@ void _component_1_update(global::Microsoft.UI.Xaml.ElementStub sender) that.Bindings.UpdateResources(); that.Bindings.NotifyXLoad("LoadElement"); } + else + { + _LoadElementSubject.ElementInstance = null; + } } } c1.MaterializationChanged += _component_1_update; diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/TXBRXLE/XamlCodeGenerator_MainPage_d6cd66944958ced0c513e0a04797b51d.cs b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/TXBRXLE/XamlCodeGenerator_MainPage_d6cd66944958ced0c513e0a04797b51d.cs index 9d80717e56b9..9c04fd3d92cb 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/TXBRXLE/XamlCodeGenerator_MainPage_d6cd66944958ced0c513e0a04797b51d.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators.Tests/XamlCodeGeneratorTests/Out/TXBRXLE/XamlCodeGenerator_MainPage_d6cd66944958ced0c513e0a04797b51d.cs @@ -108,6 +108,10 @@ void _component_1_update(global::Microsoft.UI.Xaml.ElementStub sender) that.Bindings.UpdateResources(); that.Bindings.NotifyXLoad("LoadElement"); } + else + { + _LoadElementSubject.ElementInstance = null; + } } } c1.MaterializationChanged += _component_1_update; diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs index 5beaf13c8291..bbb89fd1731e 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs @@ -6156,6 +6156,23 @@ private void BuildNameCache(XamlObjectDefinition topLevelControl) } } } + + private List FindNamesIn(XamlObjectDefinition xamlObjectDefinition) + { + var list = new List(); + foreach (var element in EnumerateSubElements(xamlObjectDefinition)) + { + var nameMember = FindMember(element, "Name"); + + if (nameMember?.Value is string name) + { + list.Add(name); + } + } + + return list; + } + /// /// Statically finds a element by name, given a xaml element root /// @@ -6362,6 +6379,15 @@ private IEnumerable EnumerateSubElements(IEnumerable SUT.panel02); - await AssertIsNullAsync(() => SUT.tb04); + Assert.IsNull(SUT.panel02); + Assert.IsNull(SUT.tb04); Assert.IsNotNull(SUT.tb05); - await AssertIsNullAsync(() => SUT.tb06); + Assert.IsNull(SUT.tb06); SUT.TopLevelVisiblity2 = false; @@ -268,25 +268,25 @@ public async Task When_Binding_xLoad_Nested() Assert.IsNotNull(SUT.tb01); Assert.IsNotNull(SUT.tb02); // Note: If not null, this usually means that the control is leaking!!! - await AssertIsNullAsync(() => SUT.panel01); - await AssertIsNullAsync(() => SUT.tb03); - await AssertIsNullAsync(() => SUT.panel02); - await AssertIsNullAsync(() => SUT.tb04); - await AssertIsNullAsync(() => SUT.tb06); - await AssertIsNullAsync(() => SUT.panel03); - await AssertIsNullAsync(() => SUT.tb05); + Assert.IsNull(SUT.panel01); + Assert.IsNull(SUT.tb03); + Assert.IsNull(SUT.panel02); + Assert.IsNull(SUT.tb04); + Assert.IsNull(SUT.tb06); + Assert.IsNull(SUT.panel03); + Assert.IsNull(SUT.tb05); SUT.TopLevelVisiblity1 = false; - await AssertIsNullAsync(() => SUT.tb01); - await AssertIsNullAsync(() => SUT.tb02); - await AssertIsNullAsync(() => SUT.panel01); - await AssertIsNullAsync(() => SUT.tb03); - await AssertIsNullAsync(() => SUT.panel02); - await AssertIsNullAsync(() => SUT.tb04); - await AssertIsNullAsync(() => SUT.panel03); - await AssertIsNullAsync(() => SUT.tb05); - await AssertIsNullAsync(() => SUT.tb06); + Assert.IsNull(SUT.tb01); + Assert.IsNull(SUT.tb02); + Assert.IsNull(SUT.panel01); + Assert.IsNull(SUT.tb03); + Assert.IsNull(SUT.panel02); + Assert.IsNull(SUT.tb04); + Assert.IsNull(SUT.panel03); + Assert.IsNull(SUT.tb05); + Assert.IsNull(SUT.tb06); } #if __ANDROID__ @@ -409,10 +409,10 @@ public async Task When_Binding_xLoad_Nested_With_ElementStub_LoadCount() Assert.IsNotNull(SUT.tb02); Assert.IsNotNull(SUT.tb03); Assert.IsNotNull(SUT.panel01); - await AssertIsNullAsync(() => SUT.panel02); - await AssertIsNullAsync(() => SUT.tb04); + Assert.IsNull(SUT.panel02); + Assert.IsNull(SUT.tb04); Assert.IsNotNull(SUT.tb05); - await AssertIsNullAsync(() => SUT.tb06); + Assert.IsNull(SUT.tb06); Assert.IsTrue(panel03Stub.Load); Assert.AreEqual(1, tb01StubChangedCount); Assert.AreEqual(1, tb02StubChangedCount); @@ -425,14 +425,14 @@ public async Task When_Binding_xLoad_Nested_With_ElementStub_LoadCount() Assert.IsNotNull(SUT.tb01); Assert.IsNotNull(SUT.tb02); - await AssertIsNullAsync(() => SUT.panel01); - await AssertIsNullAsync(() => SUT.tb03); - await AssertIsNullAsync(() => SUT.panel02); - await AssertIsNullAsync(() => SUT.tb04); - await AssertIsNullAsync(() => SUT.tb06); + Assert.IsNull(SUT.panel01); + Assert.IsNull(SUT.tb03); + Assert.IsNull(SUT.panel02); + Assert.IsNull(SUT.tb04); + Assert.IsNull(SUT.tb06); Assert.IsFalse(panel03Stub.Load); - await AssertIsNullAsync(() => SUT.panel03); - await AssertIsNullAsync(() => SUT.tb05); + Assert.IsNull(SUT.panel03); + Assert.IsNull(SUT.tb05); Assert.AreEqual(1, tb01StubChangedCount); Assert.AreEqual(1, tb02StubChangedCount); Assert.AreEqual(2, panel01StubChangedCount); @@ -442,39 +442,21 @@ public async Task When_Binding_xLoad_Nested_With_ElementStub_LoadCount() await Task.Yield(); - await AssertIsNullAsync(() => SUT.tb01); - await AssertIsNullAsync(() => SUT.tb02); - await AssertIsNullAsync(() => SUT.panel01); - await AssertIsNullAsync(() => SUT.tb03); - await AssertIsNullAsync(() => SUT.panel02); - await AssertIsNullAsync(() => SUT.tb04); + Assert.IsNull(SUT.tb01); + Assert.IsNull(SUT.tb02); + Assert.IsNull(SUT.panel01); + Assert.IsNull(SUT.tb03); + Assert.IsNull(SUT.panel02); + Assert.IsNull(SUT.tb04); Assert.IsFalse(panel03Stub.Load); - await AssertIsNullAsync(() => SUT.panel03); - await AssertIsNullAsync(() => SUT.tb05); - await AssertIsNullAsync(() => SUT.tb06); + Assert.IsNull(SUT.panel03); + Assert.IsNull(SUT.tb05); + Assert.IsNull(SUT.tb06); Assert.AreEqual(2, tb01StubChangedCount); Assert.AreEqual(2, tb02StubChangedCount); Assert.AreEqual(2, panel01StubChangedCount); Assert.AreEqual(2, panel02StubChangedCount); } - - private async Task AssertIsNullAsync(Func getter, TimeSpan? timeout = null) - { - timeout ??= TimeSpan.FromSeconds(10); - var sw = Stopwatch.StartNew(); - - while (sw.Elapsed < timeout && getter() != null) - { - await Task.Delay(100); - - // Wait for the ElementNameSubject and ComponentHolder - // instances to release their references. - GC.Collect(2); - GC.WaitForPendingFinalizers(); - } - - Assert.IsNull(getter()); - } } } #endif diff --git a/src/Uno.UI/UI/Xaml/Data/ElementNameSubject.cs b/src/Uno.UI/UI/Xaml/Data/ElementNameSubject.cs index aa9fc16e7124..4d08ffb5bd29 100644 --- a/src/Uno.UI/UI/Xaml/Data/ElementNameSubject.cs +++ b/src/Uno.UI/UI/Xaml/Data/ElementNameSubject.cs @@ -48,6 +48,12 @@ public object? ElementInstance }; set { + if (value is null) + { + _elementInstanceRef = null; + return; + } + _elementInstanceRef = WeakReferencePool.RentWeakReference(this, value); var target = _elementInstanceRef?.Target;