EffectiveValue`1.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Diagnostics.CodeAnalysis;
  5. using Avalonia.Data;
  6. using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot;
  7. namespace Avalonia.PropertyStore
  8. {
  9. /// <summary>
  10. /// Represents the active value for a property in a <see cref="ValueStore"/>.
  11. /// </summary>
  12. /// <remarks>
  13. /// Stores the active value in an <see cref="AvaloniaObject"/>'s <see cref="ValueStore"/>
  14. /// for a single property, when the value is not inherited or unset/default.
  15. /// </remarks>
  16. internal sealed class EffectiveValue<T> : EffectiveValue
  17. {
  18. private readonly StyledPropertyMetadata<T> _metadata;
  19. private T? _baseValue;
  20. private UncommonFields? _uncommon;
  21. public EffectiveValue(
  22. AvaloniaObject owner,
  23. StyledProperty<T> property,
  24. EffectiveValue<T>? inherited)
  25. {
  26. Priority = BindingPriority.Unset;
  27. BasePriority = BindingPriority.Unset;
  28. _metadata = property.GetMetadata(owner.GetType());
  29. var value = inherited is null ? _metadata.DefaultValue : inherited.Value;
  30. if (property.HasCoercion && _metadata.CoerceValue is { } coerce)
  31. {
  32. _uncommon = new()
  33. {
  34. _coerce = coerce,
  35. _uncoercedValue = value,
  36. _uncoercedBaseValue = value,
  37. };
  38. Value = coerce(owner, value);
  39. }
  40. else
  41. {
  42. Value = value;
  43. }
  44. }
  45. /// <summary>
  46. /// Gets the current effective value.
  47. /// </summary>
  48. public new T Value { get; private set; }
  49. public override void SetAndRaise(
  50. ValueStore owner,
  51. IValueEntry value,
  52. BindingPriority priority)
  53. {
  54. Debug.Assert(priority != BindingPriority.LocalValue);
  55. UpdateValueEntry(value, priority);
  56. SetAndRaiseCore(owner, (StyledProperty<T>)value.Property, GetValue(value), priority, false);
  57. if (priority > BindingPriority.LocalValue &&
  58. value.GetDataValidationState(out var state, out var error))
  59. {
  60. owner.Owner.OnUpdateDataValidation(value.Property, state, error);
  61. }
  62. }
  63. public void SetLocalValueAndRaise(
  64. ValueStore owner,
  65. StyledProperty<T> property,
  66. T value)
  67. {
  68. SetAndRaiseCore(owner, property, value, BindingPriority.LocalValue, false);
  69. }
  70. public void SetCurrentValueAndRaise(
  71. ValueStore owner,
  72. StyledProperty<T> property,
  73. T value)
  74. {
  75. IsOverridenCurrentValue = true;
  76. SetAndRaiseCore(owner, property, value, Priority, true);
  77. }
  78. public bool TryGetBaseValue([MaybeNullWhen(false)] out T value)
  79. {
  80. value = _baseValue!;
  81. return BasePriority != BindingPriority.Unset;
  82. }
  83. public override void RaiseInheritedValueChanged(
  84. AvaloniaObject owner,
  85. AvaloniaProperty property,
  86. EffectiveValue? oldValue,
  87. EffectiveValue? newValue)
  88. {
  89. Debug.Assert(oldValue is not null || newValue is not null);
  90. var p = (StyledProperty<T>)property;
  91. var o = oldValue is not null ? ((EffectiveValue<T>)oldValue).Value : _metadata.DefaultValue;
  92. var n = newValue is not null ? ((EffectiveValue<T>)newValue).Value : _metadata.DefaultValue;
  93. var priority = newValue is not null ? BindingPriority.Inherited : BindingPriority.Unset;
  94. if (!EqualityComparer<T>.Default.Equals(o, n))
  95. {
  96. owner.RaisePropertyChanged(p, o, n, priority, true);
  97. }
  98. }
  99. public override void RemoveAnimationAndRaise(ValueStore owner, AvaloniaProperty property)
  100. {
  101. Debug.Assert(Priority != BindingPriority.Animation);
  102. Debug.Assert(BasePriority != BindingPriority.Unset);
  103. UpdateValueEntry(null, BindingPriority.Animation);
  104. SetAndRaiseCore(owner, (StyledProperty<T>)property, _baseValue!, BasePriority, false);
  105. }
  106. public override void CoerceValue(ValueStore owner, AvaloniaProperty property)
  107. {
  108. if (_uncommon is null)
  109. return;
  110. SetAndRaiseCore(
  111. owner,
  112. (StyledProperty<T>)property,
  113. _uncommon._uncoercedValue!,
  114. Priority,
  115. _uncommon._uncoercedBaseValue!,
  116. BasePriority);
  117. }
  118. public override void DisposeAndRaiseUnset(ValueStore owner, AvaloniaProperty property)
  119. {
  120. ValueEntry?.Unsubscribe();
  121. BaseValueEntry?.Unsubscribe();
  122. var p = (StyledProperty<T>)property;
  123. BindingPriority priority;
  124. T oldValue;
  125. if (property.Inherits && owner.TryGetInheritedValue(property, out var i))
  126. {
  127. oldValue = ((EffectiveValue<T>)i).Value;
  128. priority = BindingPriority.Inherited;
  129. }
  130. else
  131. {
  132. oldValue = _metadata.DefaultValue;
  133. priority = BindingPriority.Unset;
  134. }
  135. if (!EqualityComparer<T>.Default.Equals(oldValue, Value))
  136. {
  137. owner.Owner.RaisePropertyChanged(p, Value, oldValue, priority, true);
  138. if (property.Inherits)
  139. owner.OnInheritedEffectiveValueDisposed(p, Value);
  140. }
  141. if (ValueEntry?.GetDataValidationState(out _, out _) ??
  142. BaseValueEntry?.GetDataValidationState(out _, out _) ??
  143. false)
  144. {
  145. owner.Owner.OnUpdateDataValidation(p, BindingValueType.UnsetValue, null);
  146. }
  147. }
  148. protected override object? GetBoxedValue() => Value;
  149. private static T GetValue(IValueEntry entry)
  150. {
  151. if (entry is IValueEntry<T> typed)
  152. return typed.GetValue();
  153. else
  154. return (T)entry.GetValue()!;
  155. }
  156. private void SetAndRaiseCore(
  157. ValueStore owner,
  158. StyledProperty<T> property,
  159. T value,
  160. BindingPriority priority,
  161. bool isOverriddenCurrentValue)
  162. {
  163. var oldValue = Value;
  164. var valueChanged = false;
  165. var baseValueChanged = false;
  166. var v = value;
  167. IsOverridenCurrentValue = isOverriddenCurrentValue;
  168. if (_uncommon?._coerce is { } coerce)
  169. v = coerce(owner.Owner, value);
  170. if (priority <= Priority)
  171. {
  172. valueChanged = !EqualityComparer<T>.Default.Equals(Value, v);
  173. Value = v;
  174. Priority = priority;
  175. if (_uncommon is not null)
  176. _uncommon._uncoercedValue = value;
  177. }
  178. if (priority <= BasePriority && priority >= BindingPriority.LocalValue)
  179. {
  180. baseValueChanged = !EqualityComparer<T>.Default.Equals(_baseValue, v);
  181. _baseValue = v;
  182. BasePriority = priority;
  183. if (_uncommon is not null)
  184. _uncommon._uncoercedBaseValue = value;
  185. }
  186. if (valueChanged)
  187. {
  188. using var notifying = PropertyNotifying.Start(owner.Owner, property);
  189. owner.Owner.RaisePropertyChanged(property, oldValue, Value, Priority, true);
  190. if (property.Inherits)
  191. owner.OnInheritedEffectiveValueChanged(property, oldValue, this);
  192. }
  193. else if (baseValueChanged)
  194. {
  195. owner.Owner.RaisePropertyChanged(property, default, _baseValue!, BasePriority, false);
  196. }
  197. }
  198. private void SetAndRaiseCore(
  199. ValueStore owner,
  200. StyledProperty<T> property,
  201. T value,
  202. BindingPriority priority,
  203. T baseValue,
  204. BindingPriority basePriority)
  205. {
  206. Debug.Assert(basePriority > BindingPriority.Animation);
  207. Debug.Assert(priority <= basePriority);
  208. var oldValue = Value;
  209. var valueChanged = false;
  210. var baseValueChanged = false;
  211. var v = value;
  212. var bv = baseValue;
  213. if (_uncommon?._coerce is { } coerce)
  214. {
  215. v = coerce(owner.Owner, value);
  216. bv = coerce(owner.Owner, baseValue);
  217. }
  218. if (!EqualityComparer<T>.Default.Equals(Value, v))
  219. {
  220. Value = v;
  221. valueChanged = true;
  222. if (_uncommon is not null)
  223. _uncommon._uncoercedValue = value;
  224. }
  225. if (!EqualityComparer<T>.Default.Equals(_baseValue, bv))
  226. {
  227. _baseValue = v;
  228. baseValueChanged = true;
  229. if (_uncommon is not null)
  230. _uncommon._uncoercedValue = baseValue;
  231. }
  232. Priority = priority;
  233. BasePriority = basePriority;
  234. if (valueChanged)
  235. {
  236. using var notifying = PropertyNotifying.Start(owner.Owner, property);
  237. owner.Owner.RaisePropertyChanged(property, oldValue, Value, Priority, true);
  238. if (property.Inherits)
  239. owner.OnInheritedEffectiveValueChanged(property, oldValue, this);
  240. }
  241. if (baseValueChanged)
  242. {
  243. owner.Owner.RaisePropertyChanged(property, default, _baseValue!, BasePriority, false);
  244. }
  245. }
  246. private class UncommonFields
  247. {
  248. public Func<AvaloniaObject, T, T>? _coerce;
  249. public T? _uncoercedValue;
  250. public T? _uncoercedBaseValue;
  251. }
  252. }
  253. }