ItemsPresenterTests_Virtualization.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. [Fact]
  142. public void Scrolling_Less_Than_A_Page_Should_Move_Recycled_Items()
  143. {
  144. var target = CreateTarget();
  145. var items = (IList<string>)target.Items;
  146. target.ApplyTemplate();
  147. target.Measure(new Size(100, 100));
  148. target.Arrange(new Rect(0, 0, 100, 100));
  149. var containers = target.Panel.Children.ToList();
  150. var scroller = (ScrollContentPresenter)target.Parent;
  151. scroller.Offset = new Vector(0, 5);
  152. var scrolledContainers = containers
  153. .Skip(5)
  154. .Take(5)
  155. .Concat(containers.Take(5)).ToList();
  156. Assert.Equal(new Vector(0, 5), ((IScrollable)target).Offset);
  157. Assert.Equal(scrolledContainers, target.Panel.Children);
  158. for (var i = 0; i < target.Panel.Children.Count; ++i)
  159. {
  160. Assert.Equal(items[i + 5], target.Panel.Children[i].DataContext);
  161. }
  162. scroller.Offset = new Vector(0, 0);
  163. Assert.Equal(new Vector(0, 0), ((IScrollable)target).Offset);
  164. Assert.Equal(containers, target.Panel.Children);
  165. var dcs = target.Panel.Children.Select(x => x.DataContext).ToList();
  166. for (var i = 0; i < target.Panel.Children.Count; ++i)
  167. {
  168. Assert.Equal(items[i], target.Panel.Children[i].DataContext);
  169. }
  170. }
  171. [Fact]
  172. public void Scrolling_More_Than_A_Page_Should_Recycle_Items()
  173. {
  174. var target = CreateTarget();
  175. var items = (IList<string>)target.Items;
  176. target.ApplyTemplate();
  177. target.Measure(new Size(100, 100));
  178. target.Arrange(new Rect(0, 0, 100, 100));
  179. var containers = target.Panel.Children.ToList();
  180. var scroller = (ScrollContentPresenter)target.Parent;
  181. scroller.Offset = new Vector(0, 10);
  182. Assert.Equal(new Vector(0, 10), ((IScrollable)target).Offset);
  183. Assert.Equal(containers, target.Panel.Children);
  184. for (var i = 0; i < target.Panel.Children.Count; ++i)
  185. {
  186. Assert.Equal(items[i + 10], target.Panel.Children[i].DataContext);
  187. }
  188. }
  189. }
  190. private static ItemsPresenter CreateTarget(
  191. ItemVirtualizationMode mode = ItemVirtualizationMode.Simple,
  192. Orientation orientation = Orientation.Vertical,
  193. bool useContainers = true,
  194. int itemCount = 20)
  195. {
  196. ItemsPresenter result;
  197. var items = Enumerable.Range(0, itemCount).Select(x => $"Item {x}").ToList();
  198. var scroller = new ScrollContentPresenter
  199. {
  200. Content = result = new TestItemsPresenter(useContainers)
  201. {
  202. Items = items,
  203. ItemsPanel = VirtualizingPanelTemplate(orientation),
  204. ItemTemplate = ItemTemplate(),
  205. VirtualizationMode = mode,
  206. }
  207. };
  208. scroller.UpdateChild();
  209. return result;
  210. }
  211. private static IDataTemplate ItemTemplate()
  212. {
  213. return new FuncDataTemplate<string>(x => new Canvas
  214. {
  215. Width = 10,
  216. Height = 10,
  217. });
  218. }
  219. private static ITemplate<IPanel> VirtualizingPanelTemplate(
  220. Orientation orientation = Orientation.Vertical)
  221. {
  222. return new FuncTemplate<IPanel>(() => new VirtualizingStackPanel
  223. {
  224. Orientation = orientation,
  225. });
  226. }
  227. private class TestItemsPresenter : ItemsPresenter
  228. {
  229. private bool _useContainers;
  230. public TestItemsPresenter(bool useContainers)
  231. {
  232. _useContainers = useContainers;
  233. }
  234. protected override IItemContainerGenerator CreateItemContainerGenerator()
  235. {
  236. return _useContainers ?
  237. new ItemContainerGenerator<TestContainer>(this, TestContainer.ContentProperty, null) :
  238. new ItemContainerGenerator(this);
  239. }
  240. }
  241. private class TestContainer : ContentControl
  242. {
  243. public TestContainer()
  244. {
  245. Width = 10;
  246. Height = 10;
  247. }
  248. }
  249. }
  250. }