diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index d89d6f3690..bf1624eab3 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -776,11 +776,16 @@ namespace Avalonia
break;
}
- var metadata = property.GetMetadata(GetType());
+ UpdateDataValidationCore(property, value.Type, value.Error);
+ }
- if (metadata.EnableDataValidation == true)
+ internal void UpdateDataValidationCore(AvaloniaProperty property,
+ BindingValueType state,
+ Exception? error)
+ {
+ if (property.GetMetadata(GetType()) is { EnableDataValidation: true })
{
- UpdateDataValidation(property, value.Type, value.Error);
+ UpdateDataValidation(property, state, error);
}
}
diff --git a/src/Avalonia.Base/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
index 6231483ff8..9fbf680a5c 100644
--- a/src/Avalonia.Base/AvaloniaObjectExtensions.cs
+++ b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
@@ -199,13 +199,11 @@ namespace Avalonia
property = property ?? throw new ArgumentNullException(nameof(property));
binding = binding ?? throw new ArgumentNullException(nameof(binding));
- var metadata = property.GetMetadata(target.GetType()) as IDirectPropertyMetadata;
-
var result = binding.Initiate(
target,
property,
anchor,
- metadata?.EnableDataValidation ?? false);
+ property.GetMetadata(target.GetType()).EnableDataValidation ?? false);
if (result != null)
{
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index 45ab293a89..24244c5068 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -227,6 +227,7 @@ namespace Avalonia
/// The default binding mode for the property.
/// A value validation callback.
/// A value coercion callback.
+ /// Whether the property is interested in data validation.
/// A
public static StyledProperty Register(
string name,
@@ -234,7 +235,8 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func? validate = null,
- Func? coerce = null)
+ Func? coerce = null,
+ bool enableDataValidation = false)
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@@ -242,7 +244,8 @@ namespace Avalonia
var metadata = new StyledPropertyMetadata(
defaultValue,
defaultBindingMode: defaultBindingMode,
- coerce: coerce);
+ coerce: coerce,
+ enableDataValidation: enableDataValidation);
var result = new StyledProperty(
name,
@@ -253,7 +256,7 @@ namespace Avalonia
AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), result);
return result;
}
-
+
///
///
/// A method that gets called before and after the property starts being notified on an
@@ -267,6 +270,7 @@ namespace Avalonia
BindingMode defaultBindingMode,
Func? validate,
Func? coerce,
+ bool enableDataValidation,
Action? notifying)
where TOwner : AvaloniaObject
{
@@ -275,7 +279,8 @@ namespace Avalonia
var metadata = new StyledPropertyMetadata(
defaultValue,
defaultBindingMode: defaultBindingMode,
- coerce: coerce);
+ coerce: coerce,
+ enableDataValidation: enableDataValidation);
var result = new StyledProperty(
name,
diff --git a/src/Avalonia.Base/AvaloniaPropertyMetadata.cs b/src/Avalonia.Base/AvaloniaPropertyMetadata.cs
index 2963567b14..62bb65351f 100644
--- a/src/Avalonia.Base/AvaloniaPropertyMetadata.cs
+++ b/src/Avalonia.Base/AvaloniaPropertyMetadata.cs
@@ -13,10 +13,13 @@ namespace Avalonia
/// Initializes a new instance of the class.
///
/// The default binding mode.
+ /// Whether the property is interested in data validation.
public AvaloniaPropertyMetadata(
- BindingMode defaultBindingMode = BindingMode.Default)
+ BindingMode defaultBindingMode = BindingMode.Default,
+ bool? enableDataValidation = null)
{
_defaultBindingMode = defaultBindingMode;
+ EnableDataValidation = enableDataValidation;
}
///
@@ -31,6 +34,17 @@ namespace Avalonia
}
}
+ ///
+ /// Gets a value indicating whether the property is interested in data validation.
+ ///
+ ///
+ /// Data validation is validation performed at the target of a binding, for example in a
+ /// view model using the INotifyDataErrorInfo interface. Only certain properties on a
+ /// control (such as a TextBox's Text property) will be interested in receiving data
+ /// validation messages so this feature must be explicitly enabled by setting this flag.
+ ///
+ public bool? EnableDataValidation { get; private set; }
+
///
/// Merges the metadata with the base metadata.
///
@@ -44,6 +58,8 @@ namespace Avalonia
{
_defaultBindingMode = baseMetadata.DefaultBindingMode;
}
+
+ EnableDataValidation ??= baseMetadata.EnableDataValidation;
}
}
}
diff --git a/src/Avalonia.Base/DirectPropertyMetadata`1.cs b/src/Avalonia.Base/DirectPropertyMetadata`1.cs
index fe1cdd0e65..451ff6ce00 100644
--- a/src/Avalonia.Base/DirectPropertyMetadata`1.cs
+++ b/src/Avalonia.Base/DirectPropertyMetadata`1.cs
@@ -21,10 +21,9 @@ namespace Avalonia
TValue unsetValue = default!,
BindingMode defaultBindingMode = BindingMode.Default,
bool? enableDataValidation = null)
- : base(defaultBindingMode)
+ : base(defaultBindingMode, enableDataValidation)
{
UnsetValue = unsetValue;
- EnableDataValidation = enableDataValidation;
}
///
@@ -32,16 +31,6 @@ namespace Avalonia
///
public TValue UnsetValue { get; private set; }
- ///
- /// Gets a value indicating whether the property is interested in data validation.
- ///
- ///
- /// Data validation is validation performed at the target of a binding, for example in a
- /// view model using the INotifyDataErrorInfo interface. Only certain properties on a
- /// control (such as a TextBox's Text property) will be interested in receiving data
- /// validation messages so this feature must be explicitly enabled by setting this flag.
- ///
- public bool? EnableDataValidation { get; private set; }
///
object? IDirectPropertyMetadata.UnsetValue => UnsetValue;
@@ -51,19 +40,9 @@ namespace Avalonia
{
base.Merge(baseMetadata, property);
- var src = baseMetadata as DirectPropertyMetadata;
-
- if (src != null)
+ if (baseMetadata is DirectPropertyMetadata src)
{
- if (UnsetValue == null)
- {
- UnsetValue = src.UnsetValue;
- }
-
- if (EnableDataValidation == null)
- {
- EnableDataValidation = src.EnableDataValidation;
- }
+ UnsetValue ??= src.UnsetValue;
}
}
}
diff --git a/src/Avalonia.Base/StyledElement.cs b/src/Avalonia.Base/StyledElement.cs
index 5b8dac2f53..10a0c5da0e 100644
--- a/src/Avalonia.Base/StyledElement.cs
+++ b/src/Avalonia.Base/StyledElement.cs
@@ -46,6 +46,7 @@ namespace Avalonia
defaultBindingMode: BindingMode.OneWay,
validate: null,
coerce: null,
+ enableDataValidation: false,
notifying: DataContextNotifying);
///
diff --git a/src/Avalonia.Base/StyledPropertyMetadata`1.cs b/src/Avalonia.Base/StyledPropertyMetadata`1.cs
index c71973fde8..6f10de3651 100644
--- a/src/Avalonia.Base/StyledPropertyMetadata`1.cs
+++ b/src/Avalonia.Base/StyledPropertyMetadata`1.cs
@@ -16,11 +16,13 @@ namespace Avalonia
/// The default value of the property.
/// The default binding mode.
/// A value coercion callback.
+ /// Whether the property is interested in data validation.
public StyledPropertyMetadata(
Optional defaultValue = default,
BindingMode defaultBindingMode = BindingMode.Default,
- Func? coerce = null)
- : base(defaultBindingMode)
+ Func? coerce = null,
+ bool enableDataValidation = false)
+ : base(defaultBindingMode, enableDataValidation)
{
_defaultValue = defaultValue;
CoerceValue = coerce;
diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs
index 7e932373c2..181596a681 100644
--- a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs
+++ b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs
@@ -198,6 +198,7 @@ namespace Avalonia.Base.UnitTests
defaultBindingMode: BindingMode.OneWay,
validate: null,
coerce: null,
+ enableDataValidation: false,
notifying: FooNotifying);
public int NotifyCount { get; private set; }