diff --git a/src/Avalonia.Base/AttachedProperty.cs b/src/Avalonia.Base/AttachedProperty.cs
index fdb04b6dfc..d1df5fa5e3 100644
--- a/src/Avalonia.Base/AttachedProperty.cs
+++ b/src/Avalonia.Base/AttachedProperty.cs
@@ -18,12 +18,14 @@ namespace Avalonia
/// The class that is registering the property.
/// The property metadata.
/// Whether the property inherits its value.
+ /// A value validation callback.
public AttachedProperty(
string name,
- Type ownerType,
+ Type ownerType,
StyledPropertyMetadata metadata,
- bool inherits = false)
- : base(name, ownerType, metadata, inherits)
+ bool inherits = false,
+ Func validate = null)
+ : base(name, ownerType, metadata, inherits, validate)
{
}
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index 8e5716a5bf..e1d4a23441 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -304,22 +304,25 @@ namespace Avalonia
/// Whether the property inherits its value.
/// The default binding mode for the property.
/// A value validation callback.
+ /// A value coercion callback.
/// A
public static AttachedProperty RegisterAttached(
string name,
TValue defaultValue = default(TValue),
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
- Func validate = null)
+ Func validate = null,
+ Func coerce = null)
where THost : IAvaloniaObject
{
Contract.Requires(name != null);
var metadata = new StyledPropertyMetadata(
defaultValue,
- defaultBindingMode: defaultBindingMode);
+ defaultBindingMode: defaultBindingMode,
+ coerce: coerce);
- var result = new AttachedProperty(name, typeof(TOwner), metadata, inherits);
+ var result = new AttachedProperty(name, typeof(TOwner), metadata, inherits, validate);
var registry = AvaloniaPropertyRegistry.Instance;
registry.Register(typeof(TOwner), result);
registry.RegisterAttached(typeof(THost), result);
@@ -336,22 +339,27 @@ namespace Avalonia
/// The default value of the property.
/// Whether the property inherits its value.
/// The default binding mode for the property.
+ /// A value validation callback.
+ /// A value coercion callback.
/// A
public static AttachedProperty RegisterAttached(
string name,
Type ownerType,
TValue defaultValue = default(TValue),
bool inherits = false,
- BindingMode defaultBindingMode = BindingMode.OneWay)
+ BindingMode defaultBindingMode = BindingMode.OneWay,
+ Func validate = null,
+ Func coerce = null)
where THost : IAvaloniaObject
{
Contract.Requires(name != null);
var metadata = new StyledPropertyMetadata(
defaultValue,
- defaultBindingMode: defaultBindingMode);
+ defaultBindingMode: defaultBindingMode,
+ coerce: coerce);
- var result = new AttachedProperty(name, ownerType, metadata, inherits);
+ var result = new AttachedProperty(name, ownerType, metadata, inherits, validate);
var registry = AvaloniaPropertyRegistry.Instance;
registry.Register(ownerType, result);
registry.RegisterAttached(typeof(THost), result);
diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs
index 6f121afbef..38ebbe5bf9 100644
--- a/src/Avalonia.Controls/DefinitionBase.cs
+++ b/src/Avalonia.Controls/DefinitionBase.cs
@@ -358,7 +358,11 @@ namespace Avalonia.Controls
///
private static bool SharedSizeGroupPropertyValueValid(string value)
{
- Contract.Requires(value != null);
+ // null is default value
+ if (value == null)
+ {
+ return true;
+ }
string id = (string)value;
diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs
index 8d8dbb03a2..11f5a66400 100644
--- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs
+++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs
@@ -20,6 +20,16 @@ namespace Avalonia.Base.UnitTests
Assert.Equal(100, target.Foo);
}
+ [Fact]
+ public void Coerces_Set_Value_Attached()
+ {
+ var target = new Class1();
+
+ target.SetValue(Class1.AttachedProperty, 150);
+
+ Assert.Equal(100, target.GetValue(Class1.AttachedProperty));
+ }
+
[Fact]
public void Coerces_Bound_Value()
{
@@ -98,6 +108,12 @@ namespace Avalonia.Base.UnitTests
defaultValue: 11,
coerce: CoerceFoo);
+ public static readonly AttachedProperty AttachedProperty =
+ AvaloniaProperty.RegisterAttached(
+ "Attached",
+ defaultValue: 11,
+ coerce: CoerceFoo);
+
public int Foo
{
get => GetValue(FooProperty);
diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs
index 70de7b449f..9e48c79106 100644
--- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs
+++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs
@@ -3,6 +3,7 @@
using System;
using System.Reactive.Subjects;
+using Avalonia.Controls;
using Xunit;
namespace Avalonia.Base.UnitTests
@@ -34,6 +35,14 @@ namespace Avalonia.Base.UnitTests
Assert.Throws(() => target.SetValue(Class1.FooProperty, 101));
}
+ [Fact]
+ public void SetValue_Throws_If_Fails_Validation_Attached()
+ {
+ var target = new Class1();
+
+ Assert.Throws(() => target.SetValue(Class1.AttachedProperty, 101));
+ }
+
[Fact]
public void Reverts_To_DefaultValue_If_Binding_Fails_Validation()
{
@@ -69,6 +78,12 @@ namespace Avalonia.Base.UnitTests
defaultValue: 11,
validate: ValidateFoo);
+ public static readonly AttachedProperty AttachedProperty =
+ AvaloniaProperty.RegisterAttached(
+ "Attached",
+ defaultValue: 11,
+ validate: ValidateFoo);
+
public static bool ValidateFoo(int value)
{
return value < 100;