ItemsPresenterTests_Virtualization.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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.Collections.Generic;
  4. using System.Linq;
  5. using Avalonia.Controls.Generators;
  6. using Avalonia.Controls.Presenters;
  7. using Avalonia.Controls.Primitives;
  8. using Avalonia.Controls.Templates;
  9. using Xunit;
  10. namespace Avalonia.Controls.UnitTests.Presenters
  11. {
  12. public class ItemsPresenterTests_Virtualization
  13. {
  14. [Fact]
  15. public void Should_Return_IsLogicalScrollEnabled_False_When_Has_No_Virtualizing_Panel()
  16. {
  17. var target = CreateTarget();
  18. target.ClearValue(ItemsPresenter.ItemsPanelProperty);
  19. target.ApplyTemplate();
  20. Assert.False(((IScrollable)target).IsLogicalScrollEnabled);
  21. }
  22. [Fact]
  23. public void Should_Return_IsLogicalScrollEnabled_False_When_VirtualizationMode_None()
  24. {
  25. var target = CreateTarget(ItemVirtualizationMode.None);
  26. target.ApplyTemplate();
  27. Assert.False(((IScrollable)target).IsLogicalScrollEnabled);
  28. }
  29. [Fact]
  30. public void Should_Return_IsLogicalScrollEnabled_False_When_Doesnt_Have_ScrollPresenter_Parent()
  31. {
  32. var target = new ItemsPresenter
  33. {
  34. ItemsPanel = VirtualizingPanelTemplate(),
  35. ItemTemplate = ItemTemplate(),
  36. VirtualizationMode = ItemVirtualizationMode.Simple,
  37. };
  38. target.ApplyTemplate();
  39. Assert.False(((IScrollable)target).IsLogicalScrollEnabled);
  40. }
  41. [Fact]
  42. public void Should_Return_IsLogicalScrollEnabled_True()
  43. {
  44. var target = CreateTarget();
  45. target.ApplyTemplate();
  46. Assert.True(((IScrollable)target).IsLogicalScrollEnabled);
  47. }
  48. [Fact]
  49. public void Should_Fill_Panel_With_Containers()
  50. {
  51. var target = CreateTarget();
  52. target.ApplyTemplate();
  53. target.Measure(new Size(100, 100));
  54. target.Arrange(new Rect(0, 0, 100, 100));
  55. Assert.Equal(10, target.Panel.Children.Count);
  56. }
  57. [Fact]
  58. public void Should_Only_Create_Enough_Containers_To_Display_All_Items()
  59. {
  60. var target = CreateTarget(itemCount: 2);
  61. target.ApplyTemplate();
  62. target.Measure(new Size(100, 100));
  63. target.Arrange(new Rect(0, 0, 100, 100));
  64. Assert.Equal(2, target.Panel.Children.Count);
  65. }
  66. [Fact]
  67. public void Initial_Item_DataContexts_Should_Be_Correct()
  68. {
  69. var target = CreateTarget();
  70. var items = (IList<string>)target.Items;
  71. target.ApplyTemplate();
  72. target.Measure(new Size(100, 100));
  73. target.Arrange(new Rect(0, 0, 100, 100));
  74. for (var i = 0; i < target.Panel.Children.Count; ++i)
  75. {
  76. Assert.Equal(items[i], target.Panel.Children[i].DataContext);
  77. }
  78. }
  79. [Fact]
  80. public void Should_Add_New_Items_When_Control_Is_Enlarged()
  81. {
  82. var target = CreateTarget();
  83. var items = (IList<string>)target.Items;
  84. target.ApplyTemplate();
  85. target.Measure(new Size(100, 100));
  86. target.Arrange(new Rect(0, 0, 100, 100));
  87. Assert.Equal(10, target.Panel.Children.Count);
  88. target.Arrange(new Rect(0, 0, 100, 120));
  89. Assert.Equal(12, target.Panel.Children.Count);
  90. for (var i = 0; i < target.Panel.Children.Count; ++i)
  91. {
  92. Assert.Equal(items[i], target.Panel.Children[i].DataContext);
  93. }
  94. }
  95. public class Simple
  96. {
  97. [Fact]
  98. public void Should_Return_Items_Count_For_Extent_Vertical()
  99. {
  100. var target = CreateTarget();
  101. target.ApplyTemplate();
  102. Assert.Equal(new Size(0, 20), ((IScrollable)target).Extent);
  103. }
  104. [Fact]
  105. public void Should_Return_Items_Count_For_Extent_Horizontal()
  106. {
  107. var target = CreateTarget(orientation: Orientation.Horizontal);
  108. target.ApplyTemplate();
  109. Assert.Equal(new Size(20, 0), ((IScrollable)target).Extent);
  110. }
  111. [Fact]
  112. public void Should_Have_Number_Of_Visible_Items_As_Viewport_Vertical()
  113. {
  114. var target = CreateTarget();
  115. target.ApplyTemplate();
  116. target.Measure(new Size(100, 100));
  117. target.Arrange(new Rect(0, 0, 100, 100));
  118. Assert.Equal(new Size(0, 10), ((IScrollable)target).Viewport);
  119. }
  120. [Fact]
  121. public void Should_Have_Number_Of_Visible_Items_As_Viewport_Horizontal()
  122. {
  123. var target = CreateTarget(orientation: Orientation.Horizontal);
  124. target.ApplyTemplate();
  125. target.Measure(new Size(100, 100));
  126. target.Arrange(new Rect(0, 0, 100, 100));
  127. Assert.Equal(new Size(10, 0), ((IScrollable)target).Viewport);
  128. }
  129. [Fact]
  130. public void Should_Remove_Items_When_Control_Is_Shrank()
  131. {
  132. var target = CreateTarget();
  133. var items = (IList<string>)target.Items;
  134. target.ApplyTemplate();
  135. target.Measure(new Size(100, 100));
  136. target.Arrange(new Rect(0, 0, 100, 100));
  137. Assert.Equal(10, target.Panel.Children.Count);
  138. target.Arrange(new Rect(0, 0, 100, 80));
  139. Assert.Equal(8, target.Panel.Children.Count);
  140. }
  141. public class WithContainers
  142. {
  143. [Fact]
  144. public void Scrolling_Less_Than_A_Page_Should_Move_Recycled_Items()
  145. {
  146. var target = CreateTarget();
  147. var items = (IList<string>)target.Items;
  148. target.ApplyTemplate();
  149. target.Measure(new Size(100, 100));
  150. target.Arrange(new Rect(0, 0, 100, 100));
  151. var containers = target.Panel.Children.ToList();
  152. var scroller = (ScrollContentPresenter)target.Parent;
  153. scroller.Offset = new Vector(0, 5);
  154. var scrolledContainers = containers
  155. .Skip(5)
  156. .Take(5)
  157. .Concat(containers.Take(5)).ToList();
  158. Assert.Equal(new Vector(0, 5), ((IScrollable)target).Offset);
  159. Assert.Equal(scrolledContainers, target.Panel.Children);
  160. for (var i = 0; i < target.Panel.Children.Count; ++i)
  161. {
  162. Assert.Equal(items[i + 5], target.Panel.Children[i].DataContext);
  163. }
  164. scroller.Offset = new Vector(0, 0);
  165. Assert.Equal(new Vector(0, 0), ((IScrollable)target).Offset);
  166. Assert.Equal(containers, target.Panel.Children);
  167. var dcs = target.Panel.Children.Select(x => x.DataContext).ToList();
  168. for (var i = 0; i < target.Panel.Children.Count; ++i)
  169. {
  170. Assert.Equal(items[i], target.Panel.Children[i].DataContext);
  171. }
  172. }
  173. [Fact]
  174. public void Scrolling_More_Than_A_Page_Should_Recycle_Items()
  175. {
  176. var target = CreateTarget(itemCount: 50);
  177. var items = (IList<string>)target.Items;
  178. target.ApplyTemplate();
  179. target.Measure(new Size(100, 100));
  180. target.Arrange(new Rect(0, 0, 100, 100));
  181. var containers = target.Panel.Children.ToList();
  182. var scroller = (ScrollContentPresenter)target.Parent;
  183. scroller.Offset = new Vector(0, 20);
  184. Assert.Equal(new Vector(0, 20), ((IScrollable)target).Offset);
  185. Assert.Equal(containers, target.Panel.Children);
  186. for (var i = 0; i < target.Panel.Children.Count; ++i)
  187. {
  188. Assert.Equal(items[i + 20], target.Panel.Children[i].DataContext);
  189. }
  190. }
  191. }
  192. }
  193. private static ItemsPresenter CreateTarget(
  194. ItemVirtualizationMode mode = ItemVirtualizationMode.Simple,
  195. Orientation orientation = Orientation.Vertical,
  196. bool useContainers = true,
  197. int itemCount = 20)
  198. {
  199. ItemsPresenter result;
  200. var items = Enumerable.Range(0, itemCount).Select(x => $"Item {x}").ToList();
  201. var scroller = new ScrollContentPresenter
  202. {
  203. Content = result = new TestItemsPresenter(useContainers)
  204. {
  205. Items = items,
  206. ItemsPanel = VirtualizingPanelTemplate(orientation),
  207. ItemTemplate = ItemTemplate(),
  208. VirtualizationMode = mode,
  209. }
  210. };
  211. scroller.UpdateChild();
  212. return result;
  213. }
  214. private static IDataTemplate ItemTemplate()
  215. {
  216. return new FuncDataTemplate<string>(x => new Canvas
  217. {
  218. Width = 10,
  219. Height = 10,
  220. });
  221. }
  222. private static ITemplate<IPanel> VirtualizingPanelTemplate(
  223. Orientation orientation = Orientation.Vertical)
  224. {
  225. return new FuncTemplate<IPanel>(() => new VirtualizingStackPanel
  226. {
  227. Orientation = orientation,
  228. });
  229. }
  230. private class TestItemsPresenter : ItemsPresenter
  231. {
  232. private bool _useContainers;
  233. public TestItemsPresenter(bool useContainers)
  234. {
  235. _useContainers = useContainers;
  236. }
  237. protected override IItemContainerGenerator CreateItemContainerGenerator()
  238. {
  239. return _useContainers ?
  240. new ItemContainerGenerator<TestContainer>(this, TestContainer.ContentProperty, null) :
  241. new ItemContainerGenerator(this);
  242. }
  243. }
  244. private class TestContainer : ContentControl
  245. {
  246. public TestContainer()
  247. {
  248. Width = 10;
  249. Height = 10;
  250. }
  251. }
  252. }
  253. }