Browse Source

Moved EnableDataValdiation to AvaloniaPropertyMetadata

Support data validation in StyledProperty bindings

Co-Authored-By: Tom Edwards <109803929+tomenscape@users.noreply.github.com>
pull/10423/head
Steven Kirk 4 years ago
parent
commit
688dbc4fdc
  1. 11
      src/Avalonia.Base/AvaloniaObject.cs
  2. 4
      src/Avalonia.Base/AvaloniaObjectExtensions.cs
  3. 13
      src/Avalonia.Base/AvaloniaProperty.cs
  4. 18
      src/Avalonia.Base/AvaloniaPropertyMetadata.cs
  5. 27
      src/Avalonia.Base/DirectPropertyMetadata`1.cs
  6. 1
      src/Avalonia.Base/StyledElement.cs
  7. 6
      src/Avalonia.Base/StyledPropertyMetadata`1.cs
  8. 1
      tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs

11
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);
}
}

4
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)
{

13
src/Avalonia.Base/AvaloniaProperty.cs

@ -227,6 +227,7 @@ namespace Avalonia
/// <param name="defaultBindingMode">The default binding mode for the property.</param>
/// <param name="validate">A value validation callback.</param>
/// <param name="coerce">A value coercion callback.</param>
/// <param name="enableDataValidation">Whether the property is interested in data validation.</param>
/// <returns>A <see cref="StyledProperty{TValue}"/></returns>
public static StyledProperty<TValue> Register<TOwner, TValue>(
string name,
@ -234,7 +235,8 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func<TValue, bool>? validate = null,
Func<AvaloniaObject, TValue, TValue>? coerce = null)
Func<AvaloniaObject, TValue, TValue>? coerce = null,
bool enableDataValidation = false)
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@ -242,7 +244,8 @@ namespace Avalonia
var metadata = new StyledPropertyMetadata<TValue>(
defaultValue,
defaultBindingMode: defaultBindingMode,
coerce: coerce);
coerce: coerce,
enableDataValidation: enableDataValidation);
var result = new StyledProperty<TValue>(
name,
@ -253,7 +256,7 @@ namespace Avalonia
AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), result);
return result;
}
/// <inheritdoc cref="Register{TOwner, TValue}" />
/// <param name="notifying">
/// A method that gets called before and after the property starts being notified on an
@ -267,6 +270,7 @@ namespace Avalonia
BindingMode defaultBindingMode,
Func<TValue, bool>? validate,
Func<AvaloniaObject, TValue, TValue>? coerce,
bool enableDataValidation,
Action<AvaloniaObject, bool>? notifying)
where TOwner : AvaloniaObject
{
@ -275,7 +279,8 @@ namespace Avalonia
var metadata = new StyledPropertyMetadata<TValue>(
defaultValue,
defaultBindingMode: defaultBindingMode,
coerce: coerce);
coerce: coerce,
enableDataValidation: enableDataValidation);
var result = new StyledProperty<TValue>(
name,

18
src/Avalonia.Base/AvaloniaPropertyMetadata.cs

@ -13,10 +13,13 @@ namespace Avalonia
/// Initializes a new instance of the <see cref="AvaloniaPropertyMetadata"/> class.
/// </summary>
/// <param name="defaultBindingMode">The default binding mode.</param>
/// <param name="enableDataValidation">Whether the property is interested in data validation.</param>
public AvaloniaPropertyMetadata(
BindingMode defaultBindingMode = BindingMode.Default)
BindingMode defaultBindingMode = BindingMode.Default,
bool? enableDataValidation = null)
{
_defaultBindingMode = defaultBindingMode;
EnableDataValidation = enableDataValidation;
}
/// <summary>
@ -31,6 +34,17 @@ namespace Avalonia
}
}
/// <summary>
/// Gets a value indicating whether the property is interested in data validation.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public bool? EnableDataValidation { get; private set; }
/// <summary>
/// Merges the metadata with the base metadata.
/// </summary>
@ -44,6 +58,8 @@ namespace Avalonia
{
_defaultBindingMode = baseMetadata.DefaultBindingMode;
}
EnableDataValidation ??= baseMetadata.EnableDataValidation;
}
}
}

27
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;
}
/// <summary>
@ -32,16 +31,6 @@ namespace Avalonia
/// </summary>
public TValue UnsetValue { get; private set; }
/// <summary>
/// Gets a value indicating whether the property is interested in data validation.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public bool? EnableDataValidation { get; private set; }
/// <inheritdoc/>
object? IDirectPropertyMetadata.UnsetValue => UnsetValue;
@ -51,19 +40,9 @@ namespace Avalonia
{
base.Merge(baseMetadata, property);
var src = baseMetadata as DirectPropertyMetadata<TValue>;
if (src != null)
if (baseMetadata is DirectPropertyMetadata<TValue> src)
{
if (UnsetValue == null)
{
UnsetValue = src.UnsetValue;
}
if (EnableDataValidation == null)
{
EnableDataValidation = src.EnableDataValidation;
}
UnsetValue ??= src.UnsetValue;
}
}
}

1
src/Avalonia.Base/StyledElement.cs

@ -46,6 +46,7 @@ namespace Avalonia
defaultBindingMode: BindingMode.OneWay,
validate: null,
coerce: null,
enableDataValidation: false,
notifying: DataContextNotifying);
/// <summary>

6
src/Avalonia.Base/StyledPropertyMetadata`1.cs

@ -16,11 +16,13 @@ namespace Avalonia
/// <param name="defaultValue">The default value of the property.</param>
/// <param name="defaultBindingMode">The default binding mode.</param>
/// <param name="coerce">A value coercion callback.</param>
/// <param name="enableDataValidation">Whether the property is interested in data validation.</param>
public StyledPropertyMetadata(
Optional<TValue> defaultValue = default,
BindingMode defaultBindingMode = BindingMode.Default,
Func<AvaloniaObject, TValue, TValue>? coerce = null)
: base(defaultBindingMode)
Func<AvaloniaObject, TValue, TValue>? coerce = null,
bool enableDataValidation = false)
: base(defaultBindingMode, enableDataValidation)
{
_defaultValue = defaultValue;
CoerceValue = coerce;

1
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; }

Loading…
Cancel
Save