ResourceDictionary.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Avalonia.Collections;
  6. namespace Avalonia.Controls
  7. {
  8. /// <summary>
  9. /// An indexed dictionary of resources.
  10. /// </summary>
  11. public class ResourceDictionary : IResourceDictionary
  12. {
  13. private Dictionary<object, object?>? _inner;
  14. private IResourceHost? _owner;
  15. private AvaloniaList<IResourceProvider>? _mergedDictionaries;
  16. /// <summary>
  17. /// Initializes a new instance of the <see cref="ResourceDictionary"/> class.
  18. /// </summary>
  19. public ResourceDictionary() { }
  20. /// <summary>
  21. /// Initializes a new instance of the <see cref="ResourceDictionary"/> class.
  22. /// </summary>
  23. public ResourceDictionary(IResourceHost owner) => Owner = owner;
  24. public int Count => _inner?.Count ?? 0;
  25. public object? this[object key]
  26. {
  27. get => _inner?[key];
  28. set
  29. {
  30. Inner[key] = value;
  31. Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
  32. }
  33. }
  34. public ICollection<object> Keys => (ICollection<object>?)_inner?.Keys ?? Array.Empty<object>();
  35. public ICollection<object?> Values => (ICollection<object?>?)_inner?.Values ?? Array.Empty<object?>();
  36. public IResourceHost? Owner
  37. {
  38. get => _owner;
  39. private set
  40. {
  41. if (_owner != value)
  42. {
  43. _owner = value;
  44. OwnerChanged?.Invoke(this, EventArgs.Empty);
  45. }
  46. }
  47. }
  48. public IList<IResourceProvider> MergedDictionaries
  49. {
  50. get
  51. {
  52. if (_mergedDictionaries == null)
  53. {
  54. _mergedDictionaries = new AvaloniaList<IResourceProvider>();
  55. _mergedDictionaries.ResetBehavior = ResetBehavior.Remove;
  56. _mergedDictionaries.ForEachItem(
  57. x =>
  58. {
  59. if (Owner is object)
  60. {
  61. x.AddOwner(Owner);
  62. }
  63. },
  64. x =>
  65. {
  66. if (Owner is object)
  67. {
  68. x.RemoveOwner(Owner);
  69. }
  70. },
  71. () => throw new NotSupportedException("Dictionary reset not supported"));
  72. }
  73. return _mergedDictionaries;
  74. }
  75. }
  76. bool IResourceNode.HasResources
  77. {
  78. get
  79. {
  80. if (_inner?.Count > 0)
  81. {
  82. return true;
  83. }
  84. if (_mergedDictionaries?.Count > 0)
  85. {
  86. foreach (var i in _mergedDictionaries)
  87. {
  88. if (i.HasResources)
  89. {
  90. return true;
  91. }
  92. }
  93. }
  94. return false;
  95. }
  96. }
  97. bool ICollection<KeyValuePair<object, object?>>.IsReadOnly => false;
  98. private Dictionary<object, object?> Inner => _inner ??= new();
  99. public event EventHandler? OwnerChanged;
  100. public void Add(object key, object? value)
  101. {
  102. Inner.Add(key, value);
  103. Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
  104. }
  105. public void Clear()
  106. {
  107. if (_inner?.Count > 0)
  108. {
  109. _inner.Clear();
  110. Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
  111. }
  112. }
  113. public bool ContainsKey(object key) => _inner?.ContainsKey(key) ?? false;
  114. public bool Remove(object key)
  115. {
  116. if (_inner?.Remove(key) == true)
  117. {
  118. Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
  119. return true;
  120. }
  121. return false;
  122. }
  123. public bool TryGetResource(object key, out object? value)
  124. {
  125. if (_inner is not null && _inner.TryGetValue(key, out value))
  126. {
  127. return true;
  128. }
  129. if (_mergedDictionaries != null)
  130. {
  131. for (var i = _mergedDictionaries.Count - 1; i >= 0; --i)
  132. {
  133. if (_mergedDictionaries[i].TryGetResource(key, out value))
  134. {
  135. return true;
  136. }
  137. }
  138. }
  139. value = null;
  140. return false;
  141. }
  142. public bool TryGetValue(object key, out object? value)
  143. {
  144. if (_inner is not null)
  145. return _inner.TryGetValue(key, out value);
  146. value = null;
  147. return false;
  148. }
  149. void ICollection<KeyValuePair<object, object?>>.Add(KeyValuePair<object, object?> item)
  150. {
  151. Add(item.Key, item.Value);
  152. }
  153. bool ICollection<KeyValuePair<object, object?>>.Contains(KeyValuePair<object, object?> item)
  154. {
  155. return (_inner as ICollection<KeyValuePair<object, object?>>)?.Contains(item) ?? false;
  156. }
  157. void ICollection<KeyValuePair<object, object?>>.CopyTo(KeyValuePair<object, object?>[] array, int arrayIndex)
  158. {
  159. (_inner as ICollection<KeyValuePair<object, object?>>)?.CopyTo(array, arrayIndex);
  160. }
  161. bool ICollection<KeyValuePair<object, object?>>.Remove(KeyValuePair<object, object?> item)
  162. {
  163. if ((_inner as ICollection<KeyValuePair<object, object?>>)?.Remove(item) == true)
  164. {
  165. Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
  166. return true;
  167. }
  168. return false;
  169. }
  170. public IEnumerator<KeyValuePair<object, object?>> GetEnumerator()
  171. {
  172. return _inner?.GetEnumerator() ?? Enumerable.Empty<KeyValuePair<object, object?>>().GetEnumerator();
  173. }
  174. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
  175. void IResourceProvider.AddOwner(IResourceHost owner)
  176. {
  177. owner = owner ?? throw new ArgumentNullException(nameof(owner));
  178. if (Owner != null)
  179. {
  180. throw new InvalidOperationException("The ResourceDictionary already has a parent.");
  181. }
  182. Owner = owner;
  183. var hasResources = _inner?.Count > 0;
  184. if (_mergedDictionaries is object)
  185. {
  186. foreach (var i in _mergedDictionaries)
  187. {
  188. i.AddOwner(owner);
  189. hasResources |= i.HasResources;
  190. }
  191. }
  192. if (hasResources)
  193. {
  194. owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
  195. }
  196. }
  197. void IResourceProvider.RemoveOwner(IResourceHost owner)
  198. {
  199. owner = owner ?? throw new ArgumentNullException(nameof(owner));
  200. if (Owner == owner)
  201. {
  202. Owner = null;
  203. var hasResources = _inner?.Count > 0;
  204. if (_mergedDictionaries is object)
  205. {
  206. foreach (var i in _mergedDictionaries)
  207. {
  208. i.RemoveOwner(owner);
  209. hasResources |= i.HasResources;
  210. }
  211. }
  212. if (hasResources)
  213. {
  214. owner.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
  215. }
  216. }
  217. }
  218. }
  219. }