From cd5307aa8c4a4ae08e7e2e808617731180527e3c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 30 Mar 2023 18:36:23 +0200 Subject: [PATCH 1/2] Added failing test. --- .../AvaloniaObjectTests_Inheritance.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs index c5cbda5325..707e1d4470 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs @@ -1,5 +1,10 @@ using System.Collections.Generic; +using Avalonia.Controls; +using Avalonia.Controls.Documents; using Avalonia.Data; +using Avalonia.Media; +using Avalonia.Styling; +using Avalonia.UnitTests; using Xunit; namespace Avalonia.Base.UnitTests @@ -90,6 +95,31 @@ namespace Avalonia.Base.UnitTests Assert.Equal(1, raised); } + [Fact] + public void ClearValue_On_Parent_Raises_PropertyChanged_On_Child_With_Inherited_Grandparent_Value() + { + var grandparent = new Class1(); + var parent = new Class2 { Parent = grandparent }; + var child = new Class2 { Parent = parent }; + var raised = 0; + + grandparent.SetValue(Class1.BazProperty, "grandparent"); + parent.SetValue(Class1.BazProperty, "parent"); + + child.PropertyChanged += (s, e) => + { + Assert.Same(child, e.Sender); + Assert.Equal("parent", e.OldValue); + Assert.Equal("grandparent", e.NewValue); + Assert.Equal(BindingPriority.Inherited, e.Priority); + ++raised; + }; + + parent.ClearValue(Class1.BazProperty); + + Assert.Equal(1, raised); + } + [Fact] public void Setting_InheritanceParent_Raises_PropertyChanged_When_Parent_Has_Value_Set() { From 683afe6e9fdfa265e44289d3f76dc297f117584c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 30 Mar 2023 18:45:48 +0200 Subject: [PATCH 2/2] Use correct newValue on inherited property change. - `oldValue` was misnamed - it's the new value - We calculated the new value and then didn't pass it to children for their property changed events: they were using the default value which may be wrong if the value is set further up the tree --- src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs | 12 ++++++------ src/Avalonia.Base/PropertyStore/ValueStore.cs | 8 +++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs b/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs index 330034f51d..6f0f6702e5 100644 --- a/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs +++ b/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs @@ -140,24 +140,24 @@ namespace Avalonia.PropertyStore var p = (StyledProperty)property; BindingPriority priority; - T oldValue; + T newValue; if (property.Inherits && owner.TryGetInheritedValue(property, out var i)) { - oldValue = ((EffectiveValue)i).Value; + newValue = ((EffectiveValue)i).Value; priority = BindingPriority.Inherited; } else { - oldValue = _metadata.DefaultValue; + newValue = _metadata.DefaultValue; priority = BindingPriority.Unset; } - if (!EqualityComparer.Default.Equals(oldValue, Value)) + if (!EqualityComparer.Default.Equals(newValue, Value)) { - owner.Owner.RaisePropertyChanged(p, Value, oldValue, priority, true); + owner.Owner.RaisePropertyChanged(p, Value, newValue, priority, true); if (property.Inherits) - owner.OnInheritedEffectiveValueDisposed(p, Value); + owner.OnInheritedEffectiveValueDisposed(p, Value, newValue); } if (ValueEntry?.GetDataValidationState(out _, out _) ?? diff --git a/src/Avalonia.Base/PropertyStore/ValueStore.cs b/src/Avalonia.Base/PropertyStore/ValueStore.cs index af31459a98..2b5a2f5022 100644 --- a/src/Avalonia.Base/PropertyStore/ValueStore.cs +++ b/src/Avalonia.Base/PropertyStore/ValueStore.cs @@ -419,7 +419,9 @@ namespace Avalonia.PropertyStore ReevaluateEffectiveValue(property, current); } else + { ReevaluateEffectiveValues(); + } } /// @@ -481,7 +483,8 @@ namespace Avalonia.PropertyStore /// /// The property whose value changed. /// The old value of the property. - public void OnInheritedEffectiveValueDisposed(StyledProperty property, T oldValue) + /// The new value of the property. + public void OnInheritedEffectiveValueDisposed(StyledProperty property, T oldValue, T newValue) { Debug.Assert(property.Inherits); @@ -489,12 +492,11 @@ namespace Avalonia.PropertyStore if (children is not null) { - var defaultValue = property.GetDefaultValue(Owner.GetType()); var count = children.Count; for (var i = 0; i < count; ++i) { - children[i].GetValueStore().OnAncestorInheritedValueChanged(property, oldValue, defaultValue); + children[i].GetValueStore().OnAncestorInheritedValueChanged(property, oldValue, newValue); } } }