|
|
|
@ -10,6 +10,8 @@ namespace Avalonia.PropertyStore |
|
|
|
{ |
|
|
|
private readonly ValueStore _owner; |
|
|
|
private IDisposable? _subscription; |
|
|
|
private T? _defaultValue; |
|
|
|
private bool _isDefaultValueInitialized; |
|
|
|
|
|
|
|
public LocalValueBindingObserver(ValueStore owner, StyledProperty<T> property) |
|
|
|
{ |
|
|
|
@ -41,26 +43,28 @@ namespace Avalonia.PropertyStore |
|
|
|
|
|
|
|
public void OnNext(T value) |
|
|
|
{ |
|
|
|
static void Execute(ValueStore owner, StyledProperty<T> property, T value) |
|
|
|
static void Execute(LocalValueBindingObserver<T> instance, T value) |
|
|
|
{ |
|
|
|
if (property.ValidateValue?.Invoke(value) != false) |
|
|
|
owner.SetValue(property, value, BindingPriority.LocalValue); |
|
|
|
else |
|
|
|
owner.ClearLocalValue(property); |
|
|
|
var owner = instance._owner; |
|
|
|
var property = instance.Property; |
|
|
|
|
|
|
|
if (property.ValidateValue?.Invoke(value) == false) |
|
|
|
value = instance.GetCachedDefaultValue(); |
|
|
|
|
|
|
|
owner.SetValue(property, value, BindingPriority.LocalValue); |
|
|
|
} |
|
|
|
|
|
|
|
if (Dispatcher.UIThread.CheckAccess()) |
|
|
|
{ |
|
|
|
Execute(_owner, Property, value); |
|
|
|
Execute(this, value); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// To avoid allocating closure in the outer scope we need to capture variables
|
|
|
|
// locally. This allows us to skip most of the allocations when on UI thread.
|
|
|
|
var instance = _owner; |
|
|
|
var property = Property; |
|
|
|
var instance = this; |
|
|
|
var newValue = value; |
|
|
|
Dispatcher.UIThread.Post(() => Execute(instance, property, newValue)); |
|
|
|
Dispatcher.UIThread.Post(() => Execute(instance, newValue)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -74,11 +78,21 @@ namespace Avalonia.PropertyStore |
|
|
|
LoggingUtils.LogIfNecessary(owner.Owner, property, value); |
|
|
|
|
|
|
|
if (value.HasValue) |
|
|
|
owner.SetValue(property, value.Value, BindingPriority.LocalValue); |
|
|
|
else if (value.Type != BindingValueType.DataValidationError) |
|
|
|
owner.ClearLocalValue(property); |
|
|
|
{ |
|
|
|
var effectiveValue = value.Value; |
|
|
|
if (property.ValidateValue?.Invoke(effectiveValue) == false) |
|
|
|
effectiveValue = instance.GetCachedDefaultValue(); |
|
|
|
owner.SetValue(property, effectiveValue, BindingPriority.LocalValue); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
owner.SetValue(property, instance.GetCachedDefaultValue(), BindingPriority.LocalValue); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (value.Type is BindingValueType.DoNothing or BindingValueType.DataValidationError) |
|
|
|
return; |
|
|
|
|
|
|
|
if (Dispatcher.UIThread.CheckAccess()) |
|
|
|
{ |
|
|
|
Execute(this, value); |
|
|
|
@ -92,5 +106,16 @@ namespace Avalonia.PropertyStore |
|
|
|
Dispatcher.UIThread.Post(() => Execute(instance, newValue)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private T GetCachedDefaultValue() |
|
|
|
{ |
|
|
|
if (!_isDefaultValueInitialized) |
|
|
|
{ |
|
|
|
_defaultValue = Property.GetDefaultValue(_owner.Owner.GetType()); |
|
|
|
_isDefaultValueInitialized = true; |
|
|
|
} |
|
|
|
|
|
|
|
return _defaultValue!; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|