diff --git a/src/Uno.UI/UI/Xaml/DependencyPropertyDetails.cs b/src/Uno.UI/UI/Xaml/DependencyPropertyDetails.cs index d1111d3e1eeb..eae378214fa8 100644 --- a/src/Uno.UI/UI/Xaml/DependencyPropertyDetails.cs +++ b/src/Uno.UI/UI/Xaml/DependencyPropertyDetails.cs @@ -184,7 +184,7 @@ private bool SetValueFast(object? value, DependencyPropertyValuePrecedences prec return false; } - internal void SetDefaultValue(object defaultValue) + internal void SetDefaultValue(object? defaultValue) { _defaultValue = defaultValue; _flags |= Flags.DefaultValueSet; diff --git a/src/Uno.UI/UI/Xaml/DependencyPropertyDetailsCollection.cs b/src/Uno.UI/UI/Xaml/DependencyPropertyDetailsCollection.cs index c623e32ba1e9..0646197a1c2a 100644 --- a/src/Uno.UI/UI/Xaml/DependencyPropertyDetailsCollection.cs +++ b/src/Uno.UI/UI/Xaml/DependencyPropertyDetailsCollection.cs @@ -39,7 +39,7 @@ partial class DependencyPropertyDetailsCollection : IDisposable private int _entriesLength; private int _minId; private int _maxId; - private DependencyObjectStore.DefaultValueProvider? _defaultValueProvider; + private List? _defaultValueProviders = null; private object? Owner => _hardOwnerReference ?? _ownerReference.Target; @@ -141,9 +141,9 @@ public DependencyPropertyDetails FindPropertyDetails(DependencyProperty property { propertyEntry = new DependencyPropertyDetails(property, _ownerType); - if(_defaultValueProvider != null && _defaultValueProvider(property, out var v)) + if (TryResolveDefaultValueFromProviders(property, out var value)) { - propertyEntry.SetDefaultValue(v); + propertyEntry.SetDefaultValue(value); } } @@ -178,9 +178,9 @@ public DependencyPropertyDetails FindPropertyDetails(DependencyProperty property ref var propertyEntry = ref Entries![property.UniqueId - _minId]; propertyEntry = new DependencyPropertyDetails(property, _ownerType); - if (_defaultValueProvider != null && _defaultValueProvider(property, out var v)) + if (TryResolveDefaultValueFromProviders(property, out var value)) { - propertyEntry.SetValue(v, DependencyPropertyValuePrecedences.DefaultValue); + propertyEntry.SetValue(value, DependencyPropertyValuePrecedences.DefaultValue); } return propertyEntry; @@ -192,6 +192,24 @@ public DependencyPropertyDetails FindPropertyDetails(DependencyProperty property } } + private bool TryResolveDefaultValueFromProviders(DependencyProperty property, out object? value) + { + if (_defaultValueProviders != null) + { + for (int i = _defaultValueProviders.Count - 1; i >= 0; i--) + { + var provider = _defaultValueProviders[i]; + if (provider.Invoke(property, out var resolvedValue)) + { + value = resolvedValue; + return true; + } + } + } + value = null; + return false; + } + private void AssignEntries(DependencyPropertyDetails[] newEntries, int newSize) { ReturnEntriesToPool(); @@ -214,9 +232,24 @@ private void ReturnEntriesToPool() internal IEnumerable GetAllDetails() => Entries.Trim(); + /// + /// Adds a default value provider. + /// + /// Default value provider. + /// + /// Providers which are registered later have higher precedence. + /// E.g. when both a derived and base class register their own default + /// value provider in the constructor for the same property, the derived + /// class value is used. + /// public void RegisterDefaultValueProvider(DependencyObjectStore.DefaultValueProvider provider) { - _defaultValueProvider = provider; + if (_defaultValueProviders == null) + { + _defaultValueProviders = new List(); + } + + _defaultValueProviders.Add(provider); } internal void TryEnableHardReferences()