ItemContainerGenerator.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using Avalonia.Controls.Presenters;
  7. using Avalonia.Controls.Templates;
  8. using Avalonia.Data;
  9. namespace Avalonia.Controls.Generators
  10. {
  11. /// <summary>
  12. /// Creates containers for items and maintains a list of created containers.
  13. /// </summary>
  14. public class ItemContainerGenerator : IItemContainerGenerator
  15. {
  16. private Dictionary<int, ItemContainerInfo> _containers = new Dictionary<int, ItemContainerInfo>();
  17. /// <summary>
  18. /// Initializes a new instance of the <see cref="ItemContainerGenerator"/> class.
  19. /// </summary>
  20. /// <param name="owner">The owner control.</param>
  21. public ItemContainerGenerator(IControl owner)
  22. {
  23. Contract.Requires<ArgumentNullException>(owner != null);
  24. Owner = owner;
  25. }
  26. /// <inheritdoc/>
  27. public IEnumerable<ItemContainerInfo> Containers => _containers.Values;
  28. /// <inheritdoc/>
  29. public event EventHandler<ItemContainerEventArgs> Materialized;
  30. /// <inheritdoc/>
  31. public event EventHandler<ItemContainerEventArgs> Dematerialized;
  32. /// <inheritdoc/>
  33. public event EventHandler<ItemContainerEventArgs> Recycled;
  34. /// <summary>
  35. /// Gets or sets the data template used to display the items in the control.
  36. /// </summary>
  37. public IDataTemplate ItemTemplate { get; set; }
  38. /// <summary>
  39. /// Gets the owner control.
  40. /// </summary>
  41. public IControl Owner { get; }
  42. /// <inheritdoc/>
  43. public ItemContainerInfo Materialize(
  44. int index,
  45. object item,
  46. IMemberSelector selector)
  47. {
  48. var i = selector != null ? selector.Select(item) : item;
  49. var container = new ItemContainerInfo(CreateContainer(i), item, index);
  50. _containers.Add(container.Index, container);
  51. Materialized?.Invoke(this, new ItemContainerEventArgs(container));
  52. return container;
  53. }
  54. /// <inheritdoc/>
  55. public virtual IEnumerable<ItemContainerInfo> Dematerialize(int startingIndex, int count)
  56. {
  57. var result = new List<ItemContainerInfo>();
  58. for (int i = startingIndex; i < startingIndex + count; ++i)
  59. {
  60. result.Add(_containers[i]);
  61. _containers.Remove(i);
  62. }
  63. Dematerialized?.Invoke(this, new ItemContainerEventArgs(startingIndex, result));
  64. return result;
  65. }
  66. /// <inheritdoc/>
  67. public virtual void InsertSpace(int index, int count)
  68. {
  69. if (count > 0)
  70. {
  71. var toMove = _containers.Where(x => x.Key >= index).ToList();
  72. foreach (var i in toMove)
  73. {
  74. _containers.Remove(i.Key);
  75. i.Value.Index += count;
  76. _containers[i.Value.Index] = i.Value;
  77. }
  78. }
  79. }
  80. /// <inheritdoc/>
  81. public virtual IEnumerable<ItemContainerInfo> RemoveRange(int startingIndex, int count)
  82. {
  83. var result = new List<ItemContainerInfo>();
  84. if (count > 0)
  85. {
  86. for (var i = startingIndex; i < startingIndex + count; ++i)
  87. {
  88. ItemContainerInfo found;
  89. if (_containers.TryGetValue(i, out found))
  90. {
  91. result.Add(found);
  92. }
  93. _containers.Remove(i);
  94. }
  95. var toMove = _containers.Where(x => x.Key >= startingIndex).ToList();
  96. foreach (var i in toMove)
  97. {
  98. _containers.Remove(i.Key);
  99. i.Value.Index -= count;
  100. _containers.Add(i.Value.Index, i.Value);
  101. }
  102. Dematerialized?.Invoke(this, new ItemContainerEventArgs(startingIndex, result));
  103. }
  104. return result;
  105. }
  106. /// <inheritdoc/>
  107. public virtual bool TryRecycle(
  108. int oldIndex,
  109. int newIndex,
  110. object item,
  111. IMemberSelector selector)
  112. {
  113. return false;
  114. }
  115. /// <inheritdoc/>
  116. public virtual IEnumerable<ItemContainerInfo> Clear()
  117. {
  118. var result = Containers.ToList();
  119. _containers.Clear();
  120. if (result.Count > 0)
  121. {
  122. Dematerialized?.Invoke(this, new ItemContainerEventArgs(0, result));
  123. }
  124. return result;
  125. }
  126. /// <inheritdoc/>
  127. public IControl ContainerFromIndex(int index)
  128. {
  129. ItemContainerInfo result;
  130. _containers.TryGetValue(index, out result);
  131. return result?.ContainerControl;
  132. }
  133. /// <inheritdoc/>
  134. public int IndexFromContainer(IControl container)
  135. {
  136. foreach (var i in _containers)
  137. {
  138. if (i.Value.ContainerControl == container)
  139. {
  140. return i.Key;
  141. }
  142. }
  143. return -1;
  144. }
  145. /// <summary>
  146. /// Creates the container for an item.
  147. /// </summary>
  148. /// <param name="item">The item.</param>
  149. /// <returns>The created container control.</returns>
  150. protected virtual IControl CreateContainer(object item)
  151. {
  152. var result = item as IControl;
  153. if (result == null)
  154. {
  155. result = new ContentPresenter();
  156. result.SetValue(ContentPresenter.ContentProperty, item, BindingPriority.Style);
  157. if (ItemTemplate != null)
  158. {
  159. result.SetValue(
  160. ContentPresenter.ContentTemplateProperty,
  161. ItemTemplate,
  162. BindingPriority.TemplatedParent);
  163. }
  164. }
  165. return result;
  166. }
  167. /// <summary>
  168. /// Moves a container.
  169. /// </summary>
  170. /// <param name="oldIndex">The old index.</param>
  171. /// <param name="newIndex">The new index.</param>
  172. /// <param name="item">The new item.</param>
  173. /// <returns>The container info.</returns>
  174. protected ItemContainerInfo MoveContainer(int oldIndex, int newIndex, object item)
  175. {
  176. var container = _containers[oldIndex];
  177. container.Index = newIndex;
  178. container.Item = item;
  179. _containers.Remove(oldIndex);
  180. _containers.Add(newIndex, container);
  181. return container;
  182. }
  183. /// <summary>
  184. /// Gets all containers with an index that fall within a range.
  185. /// </summary>
  186. /// <param name="index">The first index.</param>
  187. /// <param name="count">The number of elements in the range.</param>
  188. /// <returns>The containers.</returns>
  189. protected IEnumerable<ItemContainerInfo> GetContainerRange(int index, int count)
  190. {
  191. return _containers.Where(x => x.Key >= index && x.Key < index + count).Select(x => x.Value);
  192. }
  193. /// <summary>
  194. /// Raises the <see cref="Recycled"/> event.
  195. /// </summary>
  196. /// <param name="e">The event args.</param>
  197. protected void RaiseRecycled(ItemContainerEventArgs e)
  198. {
  199. Recycled?.Invoke(this, e);
  200. }
  201. }
  202. }