diff --git a/src/Avalonia.Base/AttachedProperty.cs b/src/Avalonia.Base/AttachedProperty.cs index 4a09f2a80a..27844023ae 100644 --- a/src/Avalonia.Base/AttachedProperty.cs +++ b/src/Avalonia.Base/AttachedProperty.cs @@ -13,16 +13,18 @@ namespace Avalonia /// /// The name of the property. /// The class that is registering the property. + /// The class that the property being is registered on. /// The property metadata. /// Whether the property inherits its value. /// A value validation callback. public AttachedProperty( string name, Type ownerType, + Type hostType, StyledPropertyMetadata metadata, bool inherits = false, Func? validate = null) - : base(name, ownerType, metadata, inherits, validate) + : base(name, ownerType, hostType, metadata, inherits, validate) { IsAttached = true; } diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs index c57131f7b5..332ca1802c 100644 --- a/src/Avalonia.Base/AvaloniaProperty.cs +++ b/src/Avalonia.Base/AvaloniaProperty.cs @@ -39,12 +39,14 @@ namespace Avalonia /// The name of the property. /// The type of the property's value. /// The type of the class that registers the property. + /// The class that the property being is registered on. /// The property metadata. /// A callback. protected AvaloniaProperty( string name, Type valueType, Type ownerType, + Type hostType, AvaloniaPropertyMetadata metadata, Action? notifying = null) { @@ -63,9 +65,9 @@ namespace Avalonia Notifying = notifying; Id = s_nextId++; - _metadata.Add(ownerType, metadata ?? throw new ArgumentNullException(nameof(metadata))); + _metadata.Add(hostType, metadata ?? throw new ArgumentNullException(nameof(metadata))); _defaultMetadata = metadata.GenerateTypeSafeMetadata(); - _singleMetadata = new(ownerType, metadata); + _singleMetadata = new(hostType, metadata); } /// @@ -255,6 +257,7 @@ namespace Avalonia var result = new StyledProperty( name, typeof(TOwner), + typeof(TOwner), metadata, inherits, validate); @@ -301,6 +304,7 @@ namespace Avalonia var result = new StyledProperty( name, typeof(TOwner), + typeof(TOwner), metadata, inherits, validate, @@ -338,7 +342,7 @@ namespace Avalonia defaultBindingMode: defaultBindingMode, coerce: coerce); - var result = new AttachedProperty(name, typeof(TOwner), metadata, inherits, validate); + var result = new AttachedProperty(name, typeof(TOwner), typeof(THost), metadata, inherits, validate); var registry = AvaloniaPropertyRegistry.Instance; registry.Register(typeof(TOwner), result); registry.RegisterAttached(typeof(THost), result); @@ -375,7 +379,7 @@ namespace Avalonia defaultBindingMode: defaultBindingMode, coerce: coerce); - var result = new AttachedProperty(name, ownerType, metadata, inherits, validate); + var result = new AttachedProperty(name, ownerType, typeof(THost), metadata, inherits, validate); var registry = AvaloniaPropertyRegistry.Instance; registry.Register(ownerType, result); registry.RegisterAttached(typeof(THost), result); diff --git a/src/Avalonia.Base/AvaloniaProperty`1.cs b/src/Avalonia.Base/AvaloniaProperty`1.cs index f8c062a176..f08c0e0a02 100644 --- a/src/Avalonia.Base/AvaloniaProperty`1.cs +++ b/src/Avalonia.Base/AvaloniaProperty`1.cs @@ -19,14 +19,16 @@ namespace Avalonia /// /// The name of the property. /// The type of the class that registers the property. + /// The class that the property being is registered on. /// The property metadata. /// A callback. protected AvaloniaProperty( string name, Type ownerType, + Type hostType, AvaloniaPropertyMetadata metadata, Action? notifying = null) - : base(name, typeof(TValue), ownerType, metadata, notifying) + : base(name, typeof(TValue), ownerType, hostType, metadata, notifying) { _changed = new LightweightSubject>(); } diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs index 7e5a962157..94694e6209 100644 --- a/src/Avalonia.Base/DirectPropertyBase.cs +++ b/src/Avalonia.Base/DirectPropertyBase.cs @@ -24,7 +24,7 @@ namespace Avalonia string name, Type ownerType, AvaloniaPropertyMetadata metadata) - : base(name, ownerType, metadata) + : base(name, ownerType, ownerType, metadata) { Owner = ownerType; } diff --git a/src/Avalonia.Base/StyledProperty.cs b/src/Avalonia.Base/StyledProperty.cs index 5cb330eda9..76ba83b88d 100644 --- a/src/Avalonia.Base/StyledProperty.cs +++ b/src/Avalonia.Base/StyledProperty.cs @@ -16,6 +16,7 @@ namespace Avalonia /// /// The name of the property. /// The type of the class that registers the property. + /// The class that the property being is registered on. /// The property metadata. /// Whether the property inherits its value. /// @@ -26,11 +27,12 @@ namespace Avalonia public StyledProperty( string name, Type ownerType, + Type hostType, StyledPropertyMetadata metadata, bool inherits = false, Func? validate = null, Action? notifying = null) - : base(name, ownerType, metadata, notifying) + : base(name, ownerType, hostType, metadata, notifying) { Inherits = inherits; ValidateValue = validate; diff --git a/tests/Avalonia.Base.UnitTests/AttachedPropertyTests.cs b/tests/Avalonia.Base.UnitTests/AttachedPropertyTests.cs index f461240d68..8a6e7b8679 100644 --- a/tests/Avalonia.Base.UnitTests/AttachedPropertyTests.cs +++ b/tests/Avalonia.Base.UnitTests/AttachedPropertyTests.cs @@ -1,3 +1,4 @@ +using Avalonia.Controls; using Xunit; namespace Avalonia.Base.UnitTests @@ -10,6 +11,7 @@ namespace Avalonia.Base.UnitTests var property = new AttachedProperty( "Foo", typeof(Class1), + typeof(Control), new StyledPropertyMetadata()); Assert.True(property.IsAttached); diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs index fe4262331f..0d0456dbda 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs @@ -31,6 +31,16 @@ namespace Avalonia.Base.UnitTests Assert.Equal(100, target.GetValue(Class1.AttachedProperty)); } + [Fact] + public void Coerces_Set_Value_Attached_On_Class_Not_Derived_From_Owner() + { + var target = new Class2(); + + target.SetValue(Class1.AttachedProperty, 150); + + Assert.Equal(100, target.GetValue(Class1.AttachedProperty)); + } + [Fact] public void Coerces_Bound_Value() { @@ -301,7 +311,7 @@ namespace Avalonia.Base.UnitTests coerce: CoerceFoo); public static readonly AttachedProperty AttachedProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( "Attached", defaultValue: 11, coerce: CoerceFoo); @@ -332,8 +342,9 @@ namespace Avalonia.Base.UnitTests public static int CoerceFoo(AvaloniaObject instance, int value) { - var o = (Class1)instance; - return Math.Clamp(value, o.MinFoo, o.MaxFoo); + return instance is Class1 o ? + Math.Clamp(value, o.MinFoo, o.MaxFoo) : + Math.Clamp(value, 0, 100); } protected override void OnPropertyChangedCore(AvaloniaPropertyChangedEventArgs change) diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs index 513aeb65ab..2b3bd07fed 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs @@ -15,6 +15,7 @@ namespace Avalonia.Base.UnitTests new StyledProperty( "BadDefault", typeof(Class1), + typeof(Class1), new StyledPropertyMetadata(101), validate: Class1.ValidateFoo)); } diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs index 0d62f20f7e..23e21c1645 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs @@ -22,7 +22,7 @@ namespace Avalonia.Base.UnitTests { var registry = new AvaloniaPropertyRegistry(); var metadata = new StyledPropertyMetadata(); - var property = new AttachedProperty("test", typeof(object), metadata, true); + var property = new AttachedProperty("test", typeof(object), typeof(object), metadata, true); registry.Register(typeof(object), property); registry.RegisterAttached(typeof(AvaloniaPropertyRegistryTests), property); property.AddOwner(); diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs index e44c15d962..d974351b1e 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs @@ -157,7 +157,7 @@ namespace Avalonia.Base.UnitTests private class TestProperty : AvaloniaProperty { public TestProperty(string name, Type ownerType, TestMetadata metadata = null) - : base(name, ownerType, metadata ?? new TestMetadata()) + : base(name, ownerType, ownerType, metadata ?? new TestMetadata()) { } diff --git a/tests/Avalonia.Base.UnitTests/StyledPropertyTests.cs b/tests/Avalonia.Base.UnitTests/StyledPropertyTests.cs index f0aa47784d..5304c74c39 100644 --- a/tests/Avalonia.Base.UnitTests/StyledPropertyTests.cs +++ b/tests/Avalonia.Base.UnitTests/StyledPropertyTests.cs @@ -9,7 +9,8 @@ namespace Avalonia.Base.UnitTests { var p1 = new StyledProperty( "p1", - typeof(Class1), + typeof(Class1), + typeof(Class1), new StyledPropertyMetadata()); var p2 = p1.AddOwner(); @@ -24,6 +25,7 @@ namespace Avalonia.Base.UnitTests var p1 = new StyledProperty( "p1", typeof(Class1), + typeof(Class1), new StyledPropertyMetadata()); var p2 = p1.AddOwner(); diff --git a/tests/Avalonia.Base.UnitTests/Utilities/AvaloniaPropertyDictionaryTests.cs b/tests/Avalonia.Base.UnitTests/Utilities/AvaloniaPropertyDictionaryTests.cs index 362eee8035..4b4aeb4344 100644 --- a/tests/Avalonia.Base.UnitTests/Utilities/AvaloniaPropertyDictionaryTests.cs +++ b/tests/Avalonia.Base.UnitTests/Utilities/AvaloniaPropertyDictionaryTests.cs @@ -18,6 +18,7 @@ namespace Avalonia.Base.UnitTests.Utilities TestProperties[i] = new StyledProperty( $"Test{i}", typeof(AvaloniaPropertyDictionaryTests), + typeof(AvaloniaPropertyDictionaryTests), new StyledPropertyMetadata()); } diff --git a/tests/Avalonia.Benchmarks/Utilities/AvaloniaPropertyDictionaryBenchmarks.cs b/tests/Avalonia.Benchmarks/Utilities/AvaloniaPropertyDictionaryBenchmarks.cs index e160c8dfa8..ef21100d1f 100644 --- a/tests/Avalonia.Benchmarks/Utilities/AvaloniaPropertyDictionaryBenchmarks.cs +++ b/tests/Avalonia.Benchmarks/Utilities/AvaloniaPropertyDictionaryBenchmarks.cs @@ -172,7 +172,7 @@ internal sealed class AvaloniaPropertyValueStoreOld internal class MockProperty : StyledProperty { - public MockProperty(string name) : base(name, typeof(object), new StyledPropertyMetadata()) + public MockProperty(string name) : base(name, typeof(object), typeof(object), new StyledPropertyMetadata()) { } }