Browse Source
To remove `InheritanceFrame` - it was unneeded, we can just point to the nearest ancestor value store with inherited values.refactor/style-priorities
4 changed files with 278 additions and 161 deletions
@ -1,34 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
using System.Diagnostics.CodeAnalysis; |
|
||||
|
|
||||
namespace Avalonia.PropertyStore |
|
||||
{ |
|
||||
internal class InheritanceFrame : Dictionary<AvaloniaProperty, EffectiveValue> |
|
||||
{ |
|
||||
public InheritanceFrame(ValueStore owner, InheritanceFrame? parent = null) |
|
||||
{ |
|
||||
Owner = owner; |
|
||||
Parent = parent; |
|
||||
} |
|
||||
|
|
||||
public ValueStore Owner { get; } |
|
||||
public InheritanceFrame? Parent { get; private set; } |
|
||||
|
|
||||
public bool TryGetFromThisOrAncestor(AvaloniaProperty property, [NotNullWhen(true)] out EffectiveValue? value) |
|
||||
{ |
|
||||
var frame = this; |
|
||||
|
|
||||
while (frame is object) |
|
||||
{ |
|
||||
if (frame.TryGetValue(property, out value)) |
|
||||
return true; |
|
||||
frame = frame.Parent; |
|
||||
} |
|
||||
|
|
||||
value = default; |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
public void SetParent(InheritanceFrame? value) => Parent = value; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,117 @@ |
|||||
|
using Xunit; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Base.UnitTests.PropertyStore |
||||
|
{ |
||||
|
public class ValueStoreTests_Inheritance |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void InheritanceAncestor_Is_Initially_Null() |
||||
|
{ |
||||
|
var parent = new Class1(); |
||||
|
var child = new Class1 { Parent = parent }; |
||||
|
var grandchild = new Class1 { Parent = child }; |
||||
|
|
||||
|
Assert.Null(parent.GetValueStore().InheritanceAncestor); |
||||
|
Assert.Null(child.GetValueStore().InheritanceAncestor); |
||||
|
Assert.Null(grandchild.GetValueStore().InheritanceAncestor); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_Value_In_Parent_Updates_InheritanceAncestor() |
||||
|
{ |
||||
|
var parent = new Class1(); |
||||
|
var child = new Class1 { Parent = parent }; |
||||
|
var grandchild = new Class1 { Parent = child }; |
||||
|
|
||||
|
parent.Foo = "changed"; |
||||
|
|
||||
|
var parentStore = parent.GetValueStore(); |
||||
|
Assert.Null(parentStore.InheritanceAncestor); |
||||
|
Assert.Same(parentStore, child.GetValueStore().InheritanceAncestor); |
||||
|
Assert.Same(parentStore, grandchild.GetValueStore().InheritanceAncestor); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_Value_In_Parent_Doesnt_Update_Grandchild_InheritanceAncestor_If_Child_Has_Value_Set() |
||||
|
{ |
||||
|
var parent = new Class1(); |
||||
|
var child = new Class1 { Parent = parent }; |
||||
|
var grandchild = new Class1 { Parent = child }; |
||||
|
|
||||
|
child.Foo = "foochanged"; |
||||
|
parent.Foo = "changed"; |
||||
|
|
||||
|
var parentStore = parent.GetValueStore(); |
||||
|
Assert.Null(parentStore.InheritanceAncestor); |
||||
|
Assert.Same(parentStore, child.GetValueStore().InheritanceAncestor); |
||||
|
Assert.Same(child.GetValueStore(), grandchild.GetValueStore().InheritanceAncestor); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Clearing_Value_In_Parent_Updates_InheritanceAncestor() |
||||
|
{ |
||||
|
var parent = new Class1(); |
||||
|
var child = new Class1 { Parent = parent }; |
||||
|
var grandchild = new Class1 { Parent = child }; |
||||
|
|
||||
|
parent.Foo = "changed"; |
||||
|
parent.ClearValue(Class1.FooProperty); |
||||
|
|
||||
|
Assert.Null(parent.GetValueStore().InheritanceAncestor); |
||||
|
Assert.Null(child.GetValueStore().InheritanceAncestor); |
||||
|
Assert.Null(grandchild.GetValueStore().InheritanceAncestor); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Clear_Value_In_Parent_Doesnt_Update_Grandchild_InheritanceAncestor_If_Child_Has_Value_Set() |
||||
|
{ |
||||
|
var parent = new Class1(); |
||||
|
var child = new Class1 { Parent = parent }; |
||||
|
var grandchild = new Class1 { Parent = child }; |
||||
|
|
||||
|
child.Foo = "foochanged"; |
||||
|
parent.Foo = "changed"; |
||||
|
parent.ClearValue(Class1.FooProperty); |
||||
|
|
||||
|
Assert.Null(parent.GetValueStore().InheritanceAncestor); |
||||
|
Assert.Null(child.GetValueStore().InheritanceAncestor); |
||||
|
Assert.Same(child.GetValueStore(), grandchild.GetValueStore().InheritanceAncestor); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Adding_Child_Sets_InheritanceAncestor() |
||||
|
{ |
||||
|
var parent = new Class1(); |
||||
|
var child = new Class1(); |
||||
|
var grandchild = new Class1 { Parent = child }; |
||||
|
|
||||
|
parent.Foo = "changed"; |
||||
|
child.Parent = parent; |
||||
|
|
||||
|
var parentStore = parent.GetValueStore(); |
||||
|
Assert.Null(parentStore.InheritanceAncestor); |
||||
|
Assert.Same(parentStore, child.GetValueStore().InheritanceAncestor); |
||||
|
Assert.Same(parentStore, grandchild.GetValueStore().InheritanceAncestor); |
||||
|
} |
||||
|
|
||||
|
private class Class1 : AvaloniaObject |
||||
|
{ |
||||
|
public static readonly StyledProperty<string> FooProperty = |
||||
|
AvaloniaProperty.Register<Class1, string>("Foo", "foodefault", inherits: true); |
||||
|
|
||||
|
public string Foo |
||||
|
{ |
||||
|
get => GetValue(FooProperty); |
||||
|
set => SetValue(FooProperty, value); |
||||
|
} |
||||
|
|
||||
|
public Class1? Parent |
||||
|
{ |
||||
|
get { return (Class1?)InheritanceParent; } |
||||
|
set { InheritanceParent = value; } |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue