From 0fcf67d1cd6e4dbf55dddc07e3ebdb5d37222c5c Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 3 Apr 2023 19:35:22 -0400 Subject: [PATCH 1/3] Add failing test --- .../Xaml/ResourceDictionaryTests.cs | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ResourceDictionaryTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ResourceDictionaryTests.cs index bea6bc4dc8..e73ef456af 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ResourceDictionaryTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ResourceDictionaryTests.cs @@ -307,6 +307,60 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml Assert.True(buttonResources.ContainsDeferredKey("Red")); } } + + [Fact] + public void Should_Be_Possible_To_Redefine_Referenced_Resource_ControlTheme() + { + using (StyledWindow()) + { + var xaml = @" + + + + + + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var windowResources = (ResourceDictionary)window.Resources; + var innerResources = (ResourceDictionary)((UserControl)window.Content!).Resources; + + var winButtonTheme = Assert.IsType(windowResources[typeof(Button)]); + var innerButtonTheme = Assert.IsType(innerResources[typeof(Button)]); + Assert.Equal(winButtonTheme, innerButtonTheme.BasedOn); + } + } + + [Fact] + public void Should_Be_Possible_To_Redefine_Referenced_Resource() + { + using (StyledWindow()) + { + var xaml = @" + + + #aaa + + + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var windowResources = (ResourceDictionary)window.Resources; + var innerResources = (ResourceDictionary)((UserControl)window.Content!).Resources; + + var winButtonTheme = Assert.IsType(windowResources["SystemAccentColor"]); + var innerButtonTheme = Assert.IsType(innerResources["SystemAccentColor"]); + Assert.Equal(winButtonTheme, innerButtonTheme); + } + } [Fact] public void Dynamically_Changing_Referenced_Resources_Works_With_DynamicResource() From 55640f0c2bc8a49ba385f376db6bdbaf64cc795b Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 3 Apr 2023 19:35:32 -0400 Subject: [PATCH 2/3] (hack?) Fix stackoverflow --- .../Controls/ResourceDictionary.cs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Base/Controls/ResourceDictionary.cs b/src/Avalonia.Base/Controls/ResourceDictionary.cs index 5123803f6e..878797d9b6 100644 --- a/src/Avalonia.Base/Controls/ResourceDictionary.cs +++ b/src/Avalonia.Base/Controls/ResourceDictionary.cs @@ -15,6 +15,7 @@ namespace Avalonia.Controls /// public class ResourceDictionary : IResourceDictionary { + private DeferredItem? s_lastDeferredItem; private Dictionary? _inner; private IResourceHost? _owner; private AvaloniaList? _mergedDictionaries; @@ -241,12 +242,27 @@ namespace Avalonia.Controls { if (value is DeferredItem deffered) { - _inner[key] = value = deffered.Factory(null) switch + // Avoid simple reentrancy, which could commonly occur on redefining the resource. + if (s_lastDeferredItem == deffered) { - ITemplateResult t => t.Result, - object v => v, - _ => null, - }; + value = null; + return false; + } + + try + { + s_lastDeferredItem = deffered; + _inner[key] = value = deffered.Factory(null) switch + { + ITemplateResult t => t.Result, + { } v => v, + _ => null, + }; + } + finally + { + s_lastDeferredItem = null; + } } return true; } From eb09e522c115bfae03c91e8bf7fdba03414e25ac Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 4 Apr 2023 11:48:20 -0400 Subject: [PATCH 3/3] Changes after review --- src/Avalonia.Base/Controls/ResourceDictionary.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Base/Controls/ResourceDictionary.cs b/src/Avalonia.Base/Controls/ResourceDictionary.cs index 878797d9b6..231a19baab 100644 --- a/src/Avalonia.Base/Controls/ResourceDictionary.cs +++ b/src/Avalonia.Base/Controls/ResourceDictionary.cs @@ -15,7 +15,7 @@ namespace Avalonia.Controls /// public class ResourceDictionary : IResourceDictionary { - private DeferredItem? s_lastDeferredItem; + private object? lastDeferredItemKey; private Dictionary? _inner; private IResourceHost? _owner; private AvaloniaList? _mergedDictionaries; @@ -243,7 +243,7 @@ namespace Avalonia.Controls if (value is DeferredItem deffered) { // Avoid simple reentrancy, which could commonly occur on redefining the resource. - if (s_lastDeferredItem == deffered) + if (lastDeferredItemKey == key) { value = null; return false; @@ -251,7 +251,7 @@ namespace Avalonia.Controls try { - s_lastDeferredItem = deffered; + lastDeferredItemKey = key; _inner[key] = value = deffered.Factory(null) switch { ITemplateResult t => t.Result, @@ -261,7 +261,7 @@ namespace Avalonia.Controls } finally { - s_lastDeferredItem = null; + lastDeferredItemKey = null; } } return true;