ValueStore.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Diagnostics.CodeAnalysis;
  5. using Avalonia.Collections.Pooled;
  6. using Avalonia.Data;
  7. using Avalonia.Diagnostics;
  8. using Avalonia.Logging;
  9. using Avalonia.Utilities;
  10. using JetBrains.Annotations;
  11. namespace Avalonia.PropertyStore
  12. {
  13. internal class ValueStore
  14. {
  15. private readonly List<ValueFrame> _frames = new();
  16. private Dictionary<int, IDisposable>? _localValueBindings;
  17. private AvaloniaPropertyDictionary<EffectiveValue> _effectiveValues;
  18. private int _inheritedValueCount;
  19. private int _frameGeneration;
  20. private int _styling;
  21. public ValueStore(AvaloniaObject owner) => Owner = owner;
  22. public AvaloniaObject Owner { get; }
  23. public ValueStore? InheritanceAncestor { get; private set; }
  24. public bool IsEvaluating { get; private set; }
  25. public IReadOnlyList<ValueFrame> Frames => _frames;
  26. public void BeginStyling() => ++_styling;
  27. public void EndStyling()
  28. {
  29. if (--_styling == 0)
  30. ReevaluateEffectiveValues();
  31. }
  32. public void AddFrame(ValueFrame style)
  33. {
  34. InsertFrame(style);
  35. ReevaluateEffectiveValues();
  36. }
  37. public IDisposable AddBinding<T>(
  38. StyledPropertyBase<T> property,
  39. IObservable<BindingValue<T>> source,
  40. BindingPriority priority)
  41. {
  42. if (priority == BindingPriority.LocalValue)
  43. {
  44. var observer = new LocalValueBindingObserver<T>(this, property);
  45. DisposeExistingLocalValueBinding(property);
  46. _localValueBindings ??= new();
  47. _localValueBindings[property.Id] = observer;
  48. observer.Start(source);
  49. return observer;
  50. }
  51. else
  52. {
  53. var effective = GetEffectiveValue(property);
  54. var frame = GetOrCreateImmediateValueFrame(property, priority, out var frameIndex);
  55. var result = frame.AddBinding(property, source);
  56. if (effective is null || priority <= effective.Priority)
  57. result.Start();
  58. return result;
  59. }
  60. }
  61. public IDisposable AddBinding<T>(
  62. StyledPropertyBase<T> property,
  63. IObservable<T> source,
  64. BindingPriority priority)
  65. {
  66. if (priority == BindingPriority.LocalValue)
  67. {
  68. var observer = new LocalValueBindingObserver<T>(this, property);
  69. DisposeExistingLocalValueBinding(property);
  70. _localValueBindings ??= new();
  71. _localValueBindings[property.Id] = observer;
  72. observer.Start(source);
  73. return observer;
  74. }
  75. else
  76. {
  77. var effective = GetEffectiveValue(property);
  78. var frame = GetOrCreateImmediateValueFrame(property, priority, out var frameIndex);
  79. var result = frame.AddBinding(property, source);
  80. if (effective is null || priority <= effective.Priority)
  81. result.Start();
  82. return result;
  83. }
  84. }
  85. public IDisposable AddBinding<T>(
  86. StyledPropertyBase<T> property,
  87. IObservable<object?> source,
  88. BindingPriority priority)
  89. {
  90. if (priority == BindingPriority.LocalValue)
  91. {
  92. var observer = new LocalValueUntypedBindingObserver<T>(this, property);
  93. DisposeExistingLocalValueBinding(property);
  94. _localValueBindings ??= new();
  95. _localValueBindings[property.Id] = observer;
  96. observer.Start(source);
  97. return observer;
  98. }
  99. else
  100. {
  101. var effective = GetEffectiveValue(property);
  102. var frame = GetOrCreateImmediateValueFrame(property, priority, out var frameIndex);
  103. var result = frame.AddBinding(property, source);
  104. if (effective is null || priority <= effective.Priority)
  105. result.Start();
  106. return result;
  107. }
  108. }
  109. public IDisposable AddBinding<T>(DirectPropertyBase<T> property, IObservable<BindingValue<T>> source)
  110. {
  111. var observer = new DirectBindingObserver<T>(this, property);
  112. DisposeExistingLocalValueBinding(property);
  113. _localValueBindings ??= new();
  114. _localValueBindings[property.Id] = observer;
  115. observer.Start(source);
  116. return observer;
  117. }
  118. public IDisposable AddBinding<T>(DirectPropertyBase<T> property, IObservable<T> source)
  119. {
  120. var observer = new DirectBindingObserver<T>(this, property);
  121. DisposeExistingLocalValueBinding(property);
  122. _localValueBindings ??= new();
  123. _localValueBindings[property.Id] = observer;
  124. observer.Start(source);
  125. return observer;
  126. }
  127. public IDisposable AddBinding<T>(DirectPropertyBase<T> property, IObservable<object?> source)
  128. {
  129. var observer = new DirectUntypedBindingObserver<T>(this, property);
  130. DisposeExistingLocalValueBinding(property);
  131. _localValueBindings ??= new();
  132. _localValueBindings[property.Id] = observer;
  133. observer.Start(source);
  134. return observer;
  135. }
  136. public void ClearLocalValue(AvaloniaProperty property)
  137. {
  138. if (TryGetEffectiveValue(property, out var effective) &&
  139. effective.Priority == BindingPriority.LocalValue)
  140. {
  141. ReevaluateEffectiveValue(property, effective, ignoreLocalValue: true);
  142. }
  143. }
  144. public IDisposable? SetValue<T>(StyledPropertyBase<T> property, T value, BindingPriority priority)
  145. {
  146. if (property.ValidateValue?.Invoke(value) == false)
  147. {
  148. throw new ArgumentException($"{value} is not a valid value for '{property.Name}.");
  149. }
  150. if (priority != BindingPriority.LocalValue)
  151. {
  152. var frame = GetOrCreateImmediateValueFrame(property, priority, out var frameIndex);
  153. var result = frame.AddValue(property, value);
  154. if (TryGetEffectiveValue(property, out var existing))
  155. {
  156. var effective = (EffectiveValue<T>)existing;
  157. effective.SetAndRaise(this, result, priority);
  158. }
  159. else
  160. {
  161. var defaultValue = property.GetDefaultValue(Owner.GetType());
  162. var effectiveValue = new EffectiveValue<T>(Owner, property, defaultValue, BindingPriority.Unset);
  163. AddEffectiveValue(property, effectiveValue);
  164. effectiveValue.SetAndRaise(this, result, priority);
  165. }
  166. return result;
  167. }
  168. else
  169. {
  170. if (TryGetEffectiveValue(property, out var existing))
  171. {
  172. var effective = (EffectiveValue<T>)existing;
  173. effective.SetLocalValueAndRaise(this, property, value);
  174. }
  175. else
  176. {
  177. var defaultValue = property.GetDefaultValue(Owner.GetType());
  178. var effectiveValue = new EffectiveValue<T>(Owner, property, defaultValue, BindingPriority.Unset);
  179. AddEffectiveValue(property, effectiveValue);
  180. effectiveValue.SetLocalValueAndRaise(this, property, value);
  181. }
  182. return null;
  183. }
  184. }
  185. public object? GetValue(AvaloniaProperty property)
  186. {
  187. if (_effectiveValues.TryGetValue(property, out var v))
  188. return v.Value;
  189. if (property.Inherits && TryGetInheritedValue(property, out v))
  190. return v.Value;
  191. return GetDefaultValue(property);
  192. }
  193. public T GetValue<T>(StyledPropertyBase<T> property)
  194. {
  195. if (_effectiveValues.TryGetValue(property, out var v))
  196. return ((EffectiveValue<T>)v).Value;
  197. if (property.Inherits && TryGetInheritedValue(property, out v))
  198. return ((EffectiveValue<T>)v).Value;
  199. return property.GetDefaultValue(Owner.GetType());
  200. }
  201. public bool IsAnimating(AvaloniaProperty property)
  202. {
  203. if (_effectiveValues.TryGetValue(property, out var v))
  204. return v.Priority <= BindingPriority.Animation;
  205. return false;
  206. }
  207. public bool IsSet(AvaloniaProperty property)
  208. {
  209. if (_effectiveValues.TryGetValue(property, out var v))
  210. return v.Priority < BindingPriority.Inherited;
  211. return false;
  212. }
  213. public void CoerceValue(AvaloniaProperty property)
  214. {
  215. if (_effectiveValues.TryGetValue(property, out var v))
  216. v.CoerceValue(this, property);
  217. }
  218. public Optional<T> GetBaseValue<T>(StyledPropertyBase<T> property)
  219. {
  220. if (TryGetEffectiveValue(property, out var v) &&
  221. ((EffectiveValue<T>)v).TryGetBaseValue(out var baseValue))
  222. {
  223. return baseValue;
  224. }
  225. return default;
  226. }
  227. public bool TryGetInheritedValue(
  228. AvaloniaProperty property,
  229. [NotNullWhen(true)] out EffectiveValue? result)
  230. {
  231. Debug.Assert(property.Inherits);
  232. var i = InheritanceAncestor;
  233. while (i is not null)
  234. {
  235. if (i.TryGetEffectiveValue(property, out result))
  236. return true;
  237. i = i.InheritanceAncestor;
  238. }
  239. result = null;
  240. return false;
  241. }
  242. public void SetInheritanceParent(AvaloniaObject? oldParent, AvaloniaObject? newParent)
  243. {
  244. var values = AvaloniaPropertyDictionaryPool<OldNewValue>.Get();
  245. var oldAncestor = InheritanceAncestor;
  246. var newAncestor = newParent?.GetValueStore();
  247. if (newAncestor?._inheritedValueCount == 0)
  248. newAncestor = newAncestor.InheritanceAncestor;
  249. // The old and new inheritance ancestors are the same, nothing to do here.
  250. if (oldAncestor == newAncestor)
  251. return;
  252. // First get the old values from the old inheritance ancestor.
  253. var f = oldAncestor;
  254. while (f is not null)
  255. {
  256. var count = f._effectiveValues.Count;
  257. for (var i = 0; i < count; ++i)
  258. {
  259. f._effectiveValues.GetKeyValue(i, out var key, out var value);
  260. if (key.Inherits)
  261. values.TryAdd(key, new(value));
  262. }
  263. f = f.InheritanceAncestor;
  264. }
  265. f = newAncestor;
  266. // Get the new values from the new inheritance ancestor.
  267. while (f is not null)
  268. {
  269. var count = f._effectiveValues.Count;
  270. for (var i = 0; i < count; ++i)
  271. {
  272. f._effectiveValues.GetKeyValue(i, out var key, out var value);
  273. if (!key.Inherits)
  274. continue;
  275. if (values.TryGetValue(key, out var existing))
  276. {
  277. if (existing.NewValue is null)
  278. values[key] = existing.WithNewValue(value);
  279. }
  280. else
  281. {
  282. values.Add(key, new(null, value));
  283. }
  284. }
  285. f = f.InheritanceAncestor;
  286. }
  287. OnInheritanceAncestorChanged(newAncestor);
  288. // Raise PropertyChanged events where necessary on this object and inheritance children.
  289. {
  290. var count = values.Count;
  291. for (var i = 0; i < count; ++i)
  292. {
  293. values.GetKeyValue(i, out var key, out var v);
  294. var oldValue = v.OldValue;
  295. var newValue = v.NewValue;
  296. if (oldValue != newValue)
  297. InheritedValueChanged(key, oldValue, newValue);
  298. }
  299. }
  300. AvaloniaPropertyDictionaryPool<OldNewValue>.Release(values);
  301. }
  302. /// <summary>
  303. /// Called by non-LocalValue binding entries to re-evaluate the effective value when the
  304. /// binding produces a new value.
  305. /// </summary>
  306. /// <param name="entry">The binding entry.</param>
  307. /// <param name="priority">The priority of binding which produced a new value.</param>
  308. public void OnBindingValueChanged(
  309. IValueEntry entry,
  310. BindingPriority priority)
  311. {
  312. Debug.Assert(priority != BindingPriority.LocalValue);
  313. var property = entry.Property;
  314. if (TryGetEffectiveValue(property, out var existing))
  315. {
  316. if (priority <= existing.Priority)
  317. ReevaluateEffectiveValue(property, existing);
  318. }
  319. else
  320. {
  321. AddEffectiveValueAndRaise(property, entry, priority);
  322. }
  323. }
  324. /// <summary>
  325. /// Called by non-LocalValue binding entries to re-evaluate the effective value when the
  326. /// binding produces an unset value.
  327. /// </summary>
  328. /// <param name="property">The bound property.</param>
  329. /// <param name="priority">The priority of binding which produced a new value.</param>
  330. public void OnBindingValueCleared(AvaloniaProperty property, BindingPriority priority)
  331. {
  332. Debug.Assert(priority != BindingPriority.LocalValue);
  333. if (TryGetEffectiveValue(property, out var existing))
  334. {
  335. if (priority <= existing.Priority)
  336. ReevaluateEffectiveValue(property, existing);
  337. }
  338. }
  339. /// <summary>
  340. /// Called by a <see cref="BindingEntryBase{TValue, TSource}"/> to re-evaluate the
  341. /// effective value when the binding completes or terminates on error.
  342. /// </summary>
  343. /// <param name="property">The previously bound property.</param>
  344. /// <param name="frame">The frame which contained the binding.</param>
  345. public void OnBindingCompleted(AvaloniaProperty property, ValueFrame frame)
  346. {
  347. var priority = frame.Priority;
  348. if (TryGetEffectiveValue(property, out var existing))
  349. {
  350. if (priority <= existing.Priority)
  351. ReevaluateEffectiveValue(property, existing);
  352. }
  353. }
  354. /// <summary>
  355. /// Called by a <see cref="ValueFrame"/> when its <see cref="ValueFrame.IsActive"/>
  356. /// state changes.
  357. /// </summary>
  358. /// <param name="frame">The frame which produced the change.</param>
  359. public void OnFrameActivationChanged(ValueFrame frame)
  360. {
  361. if (frame.EntryCount == 0)
  362. return;
  363. else if (frame.EntryCount == 1)
  364. {
  365. var property = frame.GetEntry(0).Property;
  366. _effectiveValues.TryGetValue(property, out var current);
  367. ReevaluateEffectiveValue(property, current);
  368. }
  369. else
  370. ReevaluateEffectiveValues();
  371. }
  372. /// <summary>
  373. /// Called by the parent value store when its inheritance ancestor changes.
  374. /// </summary>
  375. /// <param name="ancestor">The new inheritance ancestor.</param>
  376. public void OnInheritanceAncestorChanged(ValueStore? ancestor)
  377. {
  378. if (ancestor != this)
  379. {
  380. InheritanceAncestor = ancestor;
  381. if (_inheritedValueCount > 0)
  382. return;
  383. }
  384. var children = Owner.GetInheritanceChildren();
  385. if (children is null)
  386. return;
  387. var count = children.Count;
  388. for (var i = 0; i < count; ++i)
  389. {
  390. children[i].GetValueStore().OnInheritanceAncestorChanged(ancestor);
  391. }
  392. }
  393. /// <summary>
  394. /// Called by <see cref="EffectiveValue{T}"/> when an property with inheritance enabled
  395. /// changes its value on this value store.
  396. /// </summary>
  397. /// <param name="property">The property whose value changed.</param>
  398. /// <param name="oldValue">The old value of the property.</param>
  399. /// <param name="value">The effective value instance.</param>
  400. public void OnInheritedEffectiveValueChanged<T>(
  401. StyledPropertyBase<T> property,
  402. T oldValue,
  403. EffectiveValue<T> value)
  404. {
  405. Debug.Assert(property.Inherits);
  406. var children = Owner.GetInheritanceChildren();
  407. if (children is null)
  408. return;
  409. var count = children.Count;
  410. for (var i = 0; i < count; ++i)
  411. {
  412. children[i].GetValueStore().OnAncestorInheritedValueChanged(property, oldValue, value.Value);
  413. }
  414. }
  415. /// <summary>
  416. /// Called by <see cref="EffectiveValue{T}"/> when an property with inheritance enabled
  417. /// is removed from the effective values.
  418. /// </summary>
  419. /// <param name="property">The property whose value changed.</param>
  420. /// <param name="oldValue">The old value of the property.</param>
  421. public void OnInheritedEffectiveValueDisposed<T>(StyledPropertyBase<T> property, T oldValue)
  422. {
  423. Debug.Assert(property.Inherits);
  424. var children = Owner.GetInheritanceChildren();
  425. if (children is not null)
  426. {
  427. var defaultValue = property.GetDefaultValue(Owner.GetType());
  428. var count = children.Count;
  429. for (var i = 0; i < count; ++i)
  430. {
  431. children[i].GetValueStore().OnAncestorInheritedValueChanged(property, oldValue, defaultValue);
  432. }
  433. }
  434. }
  435. /// <summary>
  436. /// Called when a <see cref="LocalValueBindingObserver{T}"/> or
  437. /// <see cref="DirectBindingObserver{T}"/> completes.
  438. /// </summary>
  439. /// <param name="property">The previously bound property.</param>
  440. /// <param name="observer">The observer.</param>
  441. public void OnLocalValueBindingCompleted(AvaloniaProperty property, IDisposable observer)
  442. {
  443. if (_localValueBindings is not null &&
  444. _localValueBindings.TryGetValue(property.Id, out var existing))
  445. {
  446. if (existing == observer)
  447. {
  448. _localValueBindings?.Remove(property.Id);
  449. ClearLocalValue(property);
  450. }
  451. }
  452. }
  453. /// <summary>
  454. /// Called when an inherited property changes on the value store of the inheritance ancestor.
  455. /// </summary>
  456. /// <typeparam name="T">The property type.</typeparam>
  457. /// <param name="property">The property.</param>
  458. /// <param name="oldValue">The old value of the property.</param>
  459. /// <param name="newValue">The new value of the property.</param>
  460. public void OnAncestorInheritedValueChanged<T>(
  461. StyledPropertyBase<T> property,
  462. T oldValue,
  463. T newValue)
  464. {
  465. Debug.Assert(property.Inherits);
  466. // If the inherited value is set locally, propagation stops here.
  467. if (_effectiveValues.ContainsKey(property))
  468. return;
  469. using var notifying = PropertyNotifying.Start(Owner, property);
  470. Owner.RaisePropertyChanged(
  471. property,
  472. oldValue,
  473. newValue,
  474. BindingPriority.Inherited,
  475. true);
  476. var children = Owner.GetInheritanceChildren();
  477. if (children is null)
  478. return;
  479. var count = children.Count;
  480. for (var i = 0; i < count; ++i)
  481. {
  482. children[i].GetValueStore().OnAncestorInheritedValueChanged(property, oldValue, newValue);
  483. }
  484. }
  485. /// <summary>
  486. /// Called by a <see cref="ValueFrame"/> to re-evaluate the effective value when a value
  487. /// is removed.
  488. /// </summary>
  489. /// <param name="frame">The frame on which the change occurred.</param>
  490. /// <param name="property">The property whose value was removed.</param>
  491. public void OnValueEntryRemoved(ValueFrame frame, AvaloniaProperty property)
  492. {
  493. Debug.Assert(frame.IsActive);
  494. if (TryGetEffectiveValue(property, out var existing))
  495. {
  496. if (frame.Priority <= existing.Priority)
  497. ReevaluateEffectiveValue(property, existing);
  498. }
  499. else
  500. {
  501. Logger.TryGet(LogEventLevel.Error, LogArea.Property)?.Log(
  502. Owner,
  503. "Internal error: ValueStore.OnEntryRemoved called for {Property} " +
  504. "but no effective value was found.",
  505. property);
  506. Debug.Assert(false);
  507. }
  508. }
  509. public bool RemoveFrame(ValueFrame frame)
  510. {
  511. if (_frames.Remove(frame))
  512. {
  513. frame.Dispose();
  514. ++_frameGeneration;
  515. ReevaluateEffectiveValues();
  516. }
  517. return false;
  518. }
  519. public AvaloniaPropertyValue GetDiagnostic(AvaloniaProperty property)
  520. {
  521. object? value;
  522. BindingPriority priority;
  523. if (_effectiveValues.TryGetValue(property, out var v))
  524. {
  525. value = v.Value;
  526. priority = v.Priority;
  527. }
  528. else if (property.Inherits && TryGetInheritedValue(property, out v))
  529. {
  530. value = v.Value;
  531. priority = BindingPriority.Inherited;
  532. }
  533. else
  534. {
  535. value = GetDefaultValue(property);
  536. priority = BindingPriority.Unset;
  537. }
  538. return new AvaloniaPropertyValue(
  539. property,
  540. value,
  541. priority,
  542. null);
  543. }
  544. private int InsertFrame(ValueFrame frame)
  545. {
  546. // Uncomment this line when #8549 is fixed.
  547. //Debug.Assert(!_frames.Contains(frame));
  548. var index = BinarySearchFrame(frame.Priority);
  549. _frames.Insert(index, frame);
  550. ++_frameGeneration;
  551. frame.SetOwner(this);
  552. return index;
  553. }
  554. private ImmediateValueFrame GetOrCreateImmediateValueFrame(
  555. AvaloniaProperty property,
  556. BindingPriority priority,
  557. out int frameIndex)
  558. {
  559. Debug.Assert(priority != BindingPriority.LocalValue);
  560. var index = BinarySearchFrame(priority);
  561. if (index > 0 && _frames[index - 1] is ImmediateValueFrame f &&
  562. f.Priority == priority &&
  563. !f.Contains(property))
  564. {
  565. frameIndex = index - 1;
  566. return f;
  567. }
  568. var result = new ImmediateValueFrame(priority);
  569. frameIndex = InsertFrame(result);
  570. return result;
  571. }
  572. private void AddEffectiveValue(AvaloniaProperty property, EffectiveValue effectiveValue)
  573. {
  574. _effectiveValues.Add(property, effectiveValue);
  575. if (property.Inherits && _inheritedValueCount++ == 0)
  576. OnInheritanceAncestorChanged(this);
  577. }
  578. /// <summary>
  579. /// Adds a new effective value, raises the initial <see cref="AvaloniaObject.PropertyChanged"/>
  580. /// event and notifies inheritance children if necessary .
  581. /// </summary>
  582. /// <param name="property">The property.</param>
  583. /// <param name="entry">The value entry.</param>
  584. /// <param name="priority">The value priority.</param>
  585. private void AddEffectiveValueAndRaise(AvaloniaProperty property, IValueEntry entry, BindingPriority priority)
  586. {
  587. Debug.Assert(priority < BindingPriority.Inherited);
  588. var effectiveValue = property.CreateEffectiveValue(Owner);
  589. AddEffectiveValue(property, effectiveValue);
  590. effectiveValue.SetAndRaise(this, entry, priority);
  591. }
  592. private void RemoveEffectiveValue(AvaloniaProperty property, int index)
  593. {
  594. _effectiveValues.RemoveAt(index);
  595. if (property.Inherits && --_inheritedValueCount == 0)
  596. OnInheritanceAncestorChanged(InheritanceAncestor);
  597. }
  598. private bool RemoveEffectiveValue(AvaloniaProperty property)
  599. {
  600. if (_effectiveValues.Remove(property))
  601. {
  602. if (property.Inherits && --_inheritedValueCount == 0)
  603. OnInheritanceAncestorChanged(InheritanceAncestor);
  604. return true;
  605. }
  606. return false;
  607. }
  608. private bool RemoveEffectiveValue(AvaloniaProperty property, [NotNullWhen(true)] out EffectiveValue? result)
  609. {
  610. if (_effectiveValues.Remove(property, out result))
  611. {
  612. if (property.Inherits && --_inheritedValueCount == 0)
  613. OnInheritanceAncestorChanged(InheritanceAncestor);
  614. return true;
  615. }
  616. result = null;
  617. return false;
  618. }
  619. private void InheritedValueChanged(
  620. AvaloniaProperty property,
  621. EffectiveValue? oldValue,
  622. EffectiveValue? newValue)
  623. {
  624. Debug.Assert(oldValue != newValue);
  625. Debug.Assert(oldValue is not null || newValue is not null);
  626. // If the value is set locally, propagaton ends here.
  627. if (_effectiveValues.ContainsKey(property) == true)
  628. return;
  629. using var notifying = PropertyNotifying.Start(Owner, property);
  630. // Raise PropertyChanged on this object if necessary.
  631. (oldValue ?? newValue!).RaiseInheritedValueChanged(Owner, property, oldValue, newValue);
  632. var children = Owner.GetInheritanceChildren();
  633. if (children is null)
  634. return;
  635. var count = children.Count;
  636. for (var i = 0; i < count; ++i)
  637. {
  638. children[i].GetValueStore().InheritedValueChanged(property, oldValue, newValue);
  639. }
  640. }
  641. private void ReevaluateEffectiveValue(
  642. AvaloniaProperty property,
  643. EffectiveValue? current,
  644. bool ignoreLocalValue = false)
  645. {
  646. IsEvaluating = true;
  647. try
  648. {
  649. restart:
  650. // Don't reevaluate if a styling pass is in effect, reevaluation will be done when
  651. // it has finished.
  652. if (_styling > 0)
  653. return;
  654. var generation = _frameGeneration;
  655. // Notify the existing effective value that reevaluation is starting.
  656. current?.BeginReevaluation(ignoreLocalValue);
  657. // Iterate the frames to get the effective value.
  658. for (var i = _frames.Count - 1; i >= 0; --i)
  659. {
  660. var frame = _frames[i];
  661. var priority = frame.Priority;
  662. var foundEntry = frame.TryGetEntryIfActive(property, out var entry, out var activeChanged);
  663. // If the active state of the frame has changed since the last read, and
  664. // the frame holds multiple values then we need to re-evaluate the
  665. // effective values of all properties.
  666. if (activeChanged && frame.EntryCount > 1)
  667. {
  668. ReevaluateEffectiveValues();
  669. return;
  670. }
  671. // We're interested in the value if:
  672. // - There is no current effective value, or
  673. // - The value's priority is higher than the current effective value's priority, or
  674. // - The value is a non-animation value and its priority is higher than the current
  675. // effective value's base priority
  676. var isRelevantPriority = current is null ||
  677. priority < current.Priority ||
  678. (priority > BindingPriority.Animation && priority < current.BasePriority);
  679. if (foundEntry && isRelevantPriority && entry!.HasValue)
  680. {
  681. if (current is not null)
  682. {
  683. current.SetAndRaise(this, entry, priority);
  684. }
  685. else
  686. {
  687. current = property.CreateEffectiveValue(Owner);
  688. AddEffectiveValue(property, current);
  689. current.SetAndRaise(this, entry, priority);
  690. }
  691. }
  692. if (generation != _frameGeneration)
  693. goto restart;
  694. if (current?.Priority < BindingPriority.Unset &&
  695. current?.BasePriority < BindingPriority.Unset)
  696. break;
  697. }
  698. current?.EndReevaluation();
  699. if (current?.Priority == BindingPriority.Unset)
  700. {
  701. if (current.BasePriority == BindingPriority.Unset)
  702. {
  703. RemoveEffectiveValue(property);
  704. current.DisposeAndRaiseUnset(this, property);
  705. }
  706. else
  707. {
  708. current.RemoveAnimationAndRaise(this, property);
  709. }
  710. }
  711. }
  712. finally
  713. {
  714. IsEvaluating = false;
  715. }
  716. }
  717. private void ReevaluateEffectiveValues()
  718. {
  719. IsEvaluating = true;
  720. try
  721. {
  722. restart:
  723. // Don't reevaluate if a styling pass is in effect, reevaluation will be done when
  724. // it has finished.
  725. if (_styling > 0)
  726. return;
  727. var generation = _frameGeneration;
  728. var count = _effectiveValues.Count;
  729. // Notify the existing effective values that reevaluation is starting.
  730. for (var i = 0; i < count; ++i)
  731. _effectiveValues[i].BeginReevaluation();
  732. // Iterate the frames, setting and creating effective values.
  733. for (var i = _frames.Count - 1; i >= 0; --i)
  734. {
  735. var frame = _frames[i];
  736. if (!frame.IsActive)
  737. continue;
  738. var priority = frame.Priority;
  739. count = frame.EntryCount;
  740. for (var j = 0; j < count; ++j)
  741. {
  742. var entry = frame.GetEntry(j);
  743. var property = entry.Property;
  744. // Skip if we already have a value/base value for this property.
  745. if (_effectiveValues.TryGetValue(property, out var effectiveValue) &&
  746. effectiveValue.BasePriority < BindingPriority.Unset)
  747. continue;
  748. if (!entry.HasValue)
  749. continue;
  750. if (effectiveValue is not null)
  751. {
  752. effectiveValue.SetAndRaise(this, entry, priority);
  753. }
  754. else
  755. {
  756. var v = property.CreateEffectiveValue(Owner);
  757. AddEffectiveValue(property, v);
  758. v.SetAndRaise(this, entry, priority);
  759. }
  760. if (generation != _frameGeneration)
  761. goto restart;
  762. }
  763. }
  764. // Remove all effective values that are still unset.
  765. for (var i = _effectiveValues.Count - 1; i >= 0; --i)
  766. {
  767. _effectiveValues.GetKeyValue(i, out var key, out var e);
  768. e.EndReevaluation();
  769. if (e.Priority == BindingPriority.Unset)
  770. {
  771. RemoveEffectiveValue(key, i);
  772. e.DisposeAndRaiseUnset(this, key);
  773. }
  774. }
  775. }
  776. finally
  777. {
  778. IsEvaluating = false;
  779. }
  780. }
  781. private bool TryGetEffectiveValue(
  782. AvaloniaProperty property,
  783. [NotNullWhen(true)] out EffectiveValue? value)
  784. {
  785. if (_effectiveValues.TryGetValue(property, out value))
  786. return true;
  787. value = null;
  788. return false;
  789. }
  790. private EffectiveValue? GetEffectiveValue(AvaloniaProperty property)
  791. {
  792. if (_effectiveValues.TryGetValue(property, out var value))
  793. return value;
  794. return null;
  795. }
  796. private object? GetDefaultValue(AvaloniaProperty property)
  797. {
  798. return ((IStyledPropertyAccessor)property).GetDefaultValue(Owner.GetType());
  799. }
  800. private void DisposeExistingLocalValueBinding(AvaloniaProperty property)
  801. {
  802. if (_localValueBindings is not null &&
  803. _localValueBindings.TryGetValue(property.Id, out var existing))
  804. {
  805. existing.Dispose();
  806. }
  807. }
  808. private int BinarySearchFrame(BindingPriority priority)
  809. {
  810. var lo = 0;
  811. var hi = _frames.Count - 1;
  812. // Binary search insertion point.
  813. while (lo <= hi)
  814. {
  815. var i = lo + ((hi - lo) >> 1);
  816. var order = priority - _frames[i].Priority;
  817. if (order <= 0)
  818. {
  819. lo = i + 1;
  820. }
  821. else
  822. {
  823. hi = i - 1;
  824. }
  825. }
  826. return lo;
  827. }
  828. private readonly struct OldNewValue
  829. {
  830. public OldNewValue(EffectiveValue? oldValue)
  831. {
  832. OldValue = oldValue;
  833. NewValue = null;
  834. }
  835. public OldNewValue(EffectiveValue? oldValue, EffectiveValue? newValue)
  836. {
  837. OldValue = oldValue;
  838. NewValue = newValue;
  839. }
  840. public readonly EffectiveValue? OldValue;
  841. public readonly EffectiveValue? NewValue;
  842. public OldNewValue WithNewValue(EffectiveValue newValue) => new(OldValue, newValue);
  843. }
  844. }
  845. }