EffectiveValue`1.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using System.Collections.Generic;
  2. using System.Diagnostics;
  3. using System.Diagnostics.CodeAnalysis;
  4. using Avalonia.Data;
  5. namespace Avalonia.PropertyStore
  6. {
  7. /// <summary>
  8. /// Represents the active value for a property in a <see cref="ValueStore"/>.
  9. /// </summary>
  10. /// <remarks>
  11. /// Stores the active value in an <see cref="AvaloniaObject"/>'s <see cref="ValueStore"/>
  12. /// for a single property, when the value is not inherited or unset/default.
  13. /// </remarks>
  14. internal sealed class EffectiveValue<T> : EffectiveValue
  15. {
  16. private T? _baseValue;
  17. public EffectiveValue(T value, BindingPriority priority)
  18. {
  19. Value = value;
  20. Priority = priority;
  21. if (priority >= BindingPriority.LocalValue && priority < BindingPriority.Inherited)
  22. {
  23. _baseValue = value;
  24. BasePriority = priority;
  25. }
  26. else
  27. {
  28. _baseValue = default;
  29. BasePriority = BindingPriority.Unset;
  30. }
  31. }
  32. /// <summary>
  33. /// Gets the current effective value.
  34. /// </summary>
  35. public new T Value { get; private set; }
  36. public override void SetAndRaise(
  37. ValueStore owner,
  38. AvaloniaProperty property,
  39. object? value,
  40. BindingPriority priority)
  41. {
  42. // `value` should already have been converted to the correct type and
  43. // validated by this point.
  44. SetAndRaise(owner, (StyledPropertyBase<T>)property, (T)value!, priority);
  45. }
  46. public override void SetAndRaise(
  47. ValueStore owner,
  48. AvaloniaProperty property,
  49. object? value,
  50. BindingPriority priority,
  51. object? baseValue,
  52. BindingPriority basePriority)
  53. {
  54. SetAndRaise(owner, (StyledPropertyBase<T>)property, (T)value!, priority, (T)baseValue!, basePriority);
  55. }
  56. public override void SetAndRaise(
  57. ValueStore owner,
  58. IValueEntry entry,
  59. BindingPriority priority)
  60. {
  61. var value = entry is IValueEntry<T> typed ? typed.GetValue() : (T)entry.GetValue()!;
  62. SetAndRaise(owner, (StyledPropertyBase<T>)entry.Property, value, priority);
  63. }
  64. /// <summary>
  65. /// Sets the value and base value, raising <see cref="AvaloniaObject.PropertyChanged"/>
  66. /// where necessary.
  67. /// </summary>
  68. /// <param name="owner">The object on which to raise events.</param>
  69. /// <param name="property">The property being changed.</param>
  70. /// <param name="value">The new value of the property.</param>
  71. /// <param name="priority">The priority of the new value.</param>
  72. public void SetAndRaise(
  73. ValueStore owner,
  74. StyledPropertyBase<T> property,
  75. T value,
  76. BindingPriority priority)
  77. {
  78. Debug.Assert(priority < BindingPriority.Inherited);
  79. var oldValue = Value;
  80. var valueChanged = false;
  81. var baseValueChanged = false;
  82. if (priority <= Priority)
  83. {
  84. valueChanged = !EqualityComparer<T>.Default.Equals(Value, value);
  85. Value = value;
  86. Priority = priority;
  87. }
  88. if (priority <= BasePriority && priority >= BindingPriority.LocalValue)
  89. {
  90. baseValueChanged = !EqualityComparer<T>.Default.Equals(_baseValue, value);
  91. _baseValue = value;
  92. BasePriority = priority;
  93. }
  94. if (valueChanged)
  95. {
  96. owner.Owner.RaisePropertyChanged(property, oldValue, Value, Priority, true);
  97. if (property.Inherits)
  98. owner.OnInheritedEffectiveValueChanged(property, oldValue, this);
  99. }
  100. else if (baseValueChanged)
  101. {
  102. owner.Owner.RaisePropertyChanged(property, default, _baseValue!, BasePriority, false);
  103. }
  104. }
  105. /// <summary>
  106. /// Sets the value and base value, raising <see cref="AvaloniaObject.PropertyChanged"/>
  107. /// where necessary.
  108. /// </summary>
  109. /// <param name="owner">The object on which to raise events.</param>
  110. /// <param name="property">The property being changed.</param>
  111. /// <param name="value">The new value of the property.</param>
  112. /// <param name="priority">The priority of the new value.</param>
  113. /// <param name="baseValue">The new base value of the property.</param>
  114. /// <param name="basePriority">The priority of the new base value.</param>
  115. public void SetAndRaise(
  116. ValueStore owner,
  117. StyledPropertyBase<T> property,
  118. T value,
  119. BindingPriority priority,
  120. T baseValue,
  121. BindingPriority basePriority)
  122. {
  123. Debug.Assert(priority < BindingPriority.Inherited);
  124. Debug.Assert(basePriority > BindingPriority.Animation);
  125. var oldValue = Value;
  126. var valueChanged = false;
  127. var baseValueChanged = false;
  128. if (!EqualityComparer<T>.Default.Equals(Value, value))
  129. {
  130. Value = value;
  131. valueChanged = true;
  132. }
  133. if (BasePriority == BindingPriority.Unset ||
  134. !EqualityComparer<T>.Default.Equals(_baseValue, baseValue))
  135. {
  136. _baseValue = value;
  137. baseValueChanged = true;
  138. }
  139. Priority = priority;
  140. BasePriority = basePriority;
  141. if (valueChanged)
  142. {
  143. owner.Owner.RaisePropertyChanged(property, oldValue, Value, Priority, true);
  144. if (property.Inherits)
  145. owner.OnInheritedEffectiveValueChanged(property, oldValue, this);
  146. }
  147. else if (baseValueChanged)
  148. {
  149. owner.Owner.RaisePropertyChanged(property, default, _baseValue!, BasePriority, false);
  150. }
  151. }
  152. public bool TryGetBaseValue([MaybeNullWhen(false)] out T value)
  153. {
  154. value = _baseValue!;
  155. return BasePriority != BindingPriority.Unset;
  156. }
  157. public override void RaiseInheritedValueChanged(
  158. AvaloniaObject owner,
  159. AvaloniaProperty property,
  160. EffectiveValue? oldValue,
  161. EffectiveValue? newValue)
  162. {
  163. Debug.Assert(oldValue is not null || newValue is not null);
  164. var p = (StyledPropertyBase<T>)property;
  165. var o = oldValue is not null ? ((EffectiveValue<T>)oldValue).Value : p.GetDefaultValue(owner.GetType());
  166. var n = newValue is not null ? ((EffectiveValue<T>)newValue).Value : p.GetDefaultValue(owner.GetType());
  167. var priority = newValue is not null ? BindingPriority.Inherited : BindingPriority.Unset;
  168. if (!EqualityComparer<T>.Default.Equals(o, n))
  169. {
  170. owner.RaisePropertyChanged(p, o, n, priority, true);
  171. }
  172. }
  173. public override void DisposeAndRaiseUnset(ValueStore owner, AvaloniaProperty property)
  174. {
  175. DisposeAndRaiseUnset(owner, (StyledPropertyBase<T>)property);
  176. }
  177. public void DisposeAndRaiseUnset(ValueStore owner, StyledPropertyBase<T> property)
  178. {
  179. var defaultValue = property.GetDefaultValue(owner.GetType());
  180. if (!EqualityComparer<T>.Default.Equals(defaultValue, Value))
  181. {
  182. owner.Owner.RaisePropertyChanged(property, Value, defaultValue, BindingPriority.Unset, true);
  183. if (property.Inherits)
  184. owner.OnInheritedEffectiveValueDisposed(property, Value);
  185. }
  186. }
  187. protected override object? GetBoxedValue() => Value;
  188. protected override object? GetBoxedBaseValue()
  189. {
  190. return BasePriority != BindingPriority.Unset ? _baseValue : AvaloniaProperty.UnsetValue;
  191. }
  192. }
  193. }