Browse Source

Added IValueEntry.GetDataValidationState.

Implemented only on `BindingEntryBase` as only bindings can supply data validation state.
pull/10423/head
Steven Kirk 4 years ago
parent
commit
7b2a659725
  1. 67
      src/Avalonia.Base/PropertyStore/BindingEntryBase.cs
  2. 11
      src/Avalonia.Base/PropertyStore/IValueEntry.cs
  3. 8
      src/Avalonia.Base/PropertyStore/ImmediateValueEntry.cs
  4. 8
      src/Avalonia.Base/Styling/PropertySetterTemplateInstance.cs
  5. 7
      src/Avalonia.Base/Styling/Setter.cs

67
src/Avalonia.Base/PropertyStore/BindingEntryBase.cs

@ -14,23 +14,18 @@ namespace Avalonia.PropertyStore
{
private static readonly IDisposable s_creating = Disposable.Empty;
private static readonly IDisposable s_creatingQuiet = Disposable.Create(() => { });
private readonly bool _hasDataValidation;
private IDisposable? _subscription;
private bool _hasValue;
private TValue? _value;
private TValue? _defaultValue;
private bool _isDefaultValueInitialized;
private UncommonFields? _uncommon;
protected BindingEntryBase(
AvaloniaObject target,
ValueFrame frame,
AvaloniaProperty property,
IObservable<BindingValue<TSource>> source)
: this(target, frame, property, (object)source)
{
Frame = frame;
Source = source;
Property = property;
_hasDataValidation = property.GetMetadata(target.GetType()).EnableDataValidation ?? false;
}
protected BindingEntryBase(
@ -38,11 +33,21 @@ namespace Avalonia.PropertyStore
ValueFrame frame,
AvaloniaProperty property,
IObservable<TSource> source)
: this(target, frame, property, (object)source)
{
}
private BindingEntryBase(
AvaloniaObject target,
ValueFrame frame,
AvaloniaProperty property,
object source)
{
Frame = frame;
Source = source;
Property = property;
_hasDataValidation = property.GetMetadata(target.GetType()).EnableDataValidation ?? false;
Source = source;
if (property.GetMetadata(target.GetType()).EnableDataValidation == true)
_uncommon = new() { _hasDataValidation = true };
}
public bool HasValue
@ -74,6 +79,20 @@ namespace Avalonia.PropertyStore
return _value!;
}
public bool GetDataValidationState(out BindingValueType state, out Exception? error)
{
if (_uncommon?._hasDataValidation == true)
{
state = _uncommon._dataValidationState;
error = _uncommon._dataValidationError;
return true;
}
state = BindingValueType.Value;
error = null;
return false;
}
public void Start() => Start(true);
public void OnCompleted() => BindingCompleted();
@ -85,9 +104,6 @@ namespace Avalonia.PropertyStore
{
_subscription?.Dispose();
_subscription = null;
if (_hasDataValidation)
Frame.Owner?.Owner.OnUpdateDataValidation(Property, BindingValueType.UnsetValue, null);
}
object? IValueEntry.GetValue()
@ -132,6 +148,12 @@ namespace Avalonia.PropertyStore
if (!value.HasValue && value.Type != BindingValueType.DataValidationError)
value = value.WithValue(instance.GetCachedDefaultValue());
if (instance._uncommon?._hasDataValidation == true)
{
instance._uncommon._dataValidationState = value.Type;
instance._uncommon._dataValidationError = value.Error;
}
if (value.HasValue &&
(!instance._hasValue || !EqualityComparer<TValue>.Default.Equals(instance._value, value.Value)))
{
@ -140,9 +162,6 @@ namespace Avalonia.PropertyStore
if (instance._subscription is not null && instance._subscription != s_creatingQuiet)
instance.Frame.Owner?.OnBindingValueChanged(instance, instance.Frame.Priority);
}
if (instance._hasDataValidation)
owner.OnUpdateDataValidation(property, originalType, value.Error);
}
if (value.Type == BindingValueType.DoNothing)
@ -170,13 +189,23 @@ namespace Avalonia.PropertyStore
private TValue GetCachedDefaultValue()
{
if (!_isDefaultValueInitialized)
if (_uncommon?._isDefaultValueInitialized != true)
{
_defaultValue = GetDefaultValue(Frame.Owner!.Owner.GetType());
_isDefaultValueInitialized = true;
_uncommon ??= new();
_uncommon._defaultValue = GetDefaultValue(Frame.Owner!.Owner.GetType());
_uncommon._isDefaultValueInitialized = true;
}
return _defaultValue!;
return _uncommon._defaultValue!;
}
private class UncommonFields
{
public TValue? _defaultValue;
public bool _isDefaultValueInitialized;
public bool _hasDataValidation;
public BindingValueType _dataValidationState;
public Exception? _dataValidationError;
}
}
}

11
src/Avalonia.Base/PropertyStore/IValueEntry.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Data;
namespace Avalonia.PropertyStore
{
@ -22,6 +23,16 @@ namespace Avalonia.PropertyStore
/// </exception>
object? GetValue();
/// <summary>
/// Gets the data validation state if supported.
/// </summary>
/// <param name="state">The binding validation state.</param>
/// <param name="error">The current binding error, if any.</param>
/// <returns>
/// True if the entry supports data validation, otherwise false.
/// </returns>
bool GetDataValidationState(out BindingValueType state, out Exception? error);
/// <summary>
/// Called when the value entry is removed from the value store.
/// </summary>

8
src/Avalonia.Base/PropertyStore/ImmediateValueEntry.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Data;
namespace Avalonia.PropertyStore
{
@ -27,5 +28,12 @@ namespace Avalonia.PropertyStore
object? IValueEntry.GetValue() => _value;
T IValueEntry<T>.GetValue() => _value;
bool IValueEntry.GetDataValidationState(out BindingValueType state, out Exception? error)
{
state = BindingValueType.Value;
error = null;
return false;
}
}
}

8
src/Avalonia.Base/Styling/PropertySetterTemplateInstance.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Data;
using Avalonia.PropertyStore;
namespace Avalonia.Styling
@ -19,6 +20,13 @@ namespace Avalonia.Styling
public object? GetValue() => _value ??= _template.Build();
bool IValueEntry.GetDataValidationState(out BindingValueType state, out Exception? error)
{
state = BindingValueType.Value;
error = null;
return false;
}
void IValueEntry.Unsubscribe() { }
}
}

7
src/Avalonia.Base/Styling/Setter.cs

@ -90,6 +90,13 @@ namespace Avalonia.Styling
object? IValueEntry.GetValue() => Value;
bool IValueEntry.GetDataValidationState(out BindingValueType state, out Exception? error)
{
state = BindingValueType.Value;
error = null;
return false;
}
private AvaloniaProperty EnsureProperty()
{
return Property ?? throw new InvalidOperationException("Setter.Property must be set.");

Loading…
Cancel
Save