TemplatedControlTests.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // Copyright (c) The Perspex 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 Perspex.Collections;
  7. using Perspex.Controls.Presenters;
  8. using Perspex.Controls.Primitives;
  9. using Perspex.Controls.Templates;
  10. using Perspex.LogicalTree;
  11. using Perspex.VisualTree;
  12. using Xunit;
  13. namespace Perspex.Controls.UnitTests.Primitives
  14. {
  15. public class TemplatedControlTests
  16. {
  17. [Fact]
  18. public void ApplyTemplate_Should_Create_Visual_Child()
  19. {
  20. var target = new TemplatedControl
  21. {
  22. Template = new ControlTemplate(_ => new Decorator
  23. {
  24. Child = new Panel
  25. {
  26. Children = new Controls
  27. {
  28. new TextBlock(),
  29. new Border(),
  30. }
  31. }
  32. }),
  33. };
  34. target.ApplyTemplate();
  35. var types = target.GetVisualDescendents().Select(x => x.GetType()).ToList();
  36. Assert.Equal(
  37. new[]
  38. {
  39. typeof(Decorator),
  40. typeof(Panel),
  41. typeof(TextBlock),
  42. typeof(Border)
  43. },
  44. types);
  45. Assert.Empty(target.GetLogicalChildren());
  46. }
  47. [Fact]
  48. public void Templated_Children_Should_Have_TemplatedParent_Set()
  49. {
  50. var target = new TemplatedControl
  51. {
  52. Template = new ControlTemplate(_ => new Decorator
  53. {
  54. Child = new Panel
  55. {
  56. Children = new Controls
  57. {
  58. new TextBlock(),
  59. new Border(),
  60. }
  61. }
  62. }),
  63. };
  64. target.ApplyTemplate();
  65. var templatedParents = target.GetVisualDescendents()
  66. .OfType<IControl>()
  67. .Select(x => x.TemplatedParent)
  68. .ToList();
  69. Assert.Equal(4, templatedParents.Count);
  70. Assert.True(templatedParents.All(x => x == target));
  71. }
  72. [Fact]
  73. public void Templated_Child_Should_Have_Parent_Set()
  74. {
  75. var target = new TemplatedControl
  76. {
  77. Template = new ControlTemplate(_ => new Decorator())
  78. };
  79. target.ApplyTemplate();
  80. var child = (Decorator)target.GetVisualChildren().Single();
  81. Assert.Equal(target, child.Parent);
  82. Assert.Equal(target, child.GetLogicalParent());
  83. }
  84. [Fact]
  85. public void Templated_Child_Should_Have_ApplyTemplate_Called_With_Logical_Then_Visual_Parent()
  86. {
  87. var target = new TemplatedControl
  88. {
  89. Template = new ControlTemplate(_ => new ApplyTemplateTracker())
  90. };
  91. target.ApplyTemplate();
  92. var child = (ApplyTemplateTracker)target.GetVisualChildren().Single();
  93. Assert.Equal(
  94. new[]
  95. {
  96. new Tuple<IVisual, ILogical>(null, target),
  97. new Tuple<IVisual, ILogical>(target, target),
  98. },
  99. child.Invocations);
  100. }
  101. [Fact]
  102. public void Nested_TemplatedControls_Should_Be_Expanded_And_Have_Correct_TemplatedParent()
  103. {
  104. var target = new ItemsControl
  105. {
  106. Template = new ControlTemplate<ItemsControl>(ItemsControlTemplate),
  107. Items = new[] { "Foo", }
  108. };
  109. target.ApplyTemplate();
  110. var scrollViewer = target.GetVisualDescendents()
  111. .OfType<ScrollViewer>()
  112. .Single();
  113. var types = target.GetVisualDescendents()
  114. .Select(x => x.GetType())
  115. .ToList();
  116. var templatedParents = target.GetVisualDescendents()
  117. .OfType<IControl>()
  118. .Select(x => x.TemplatedParent)
  119. .ToList();
  120. Assert.Equal(
  121. new[]
  122. {
  123. typeof(Border),
  124. typeof(ScrollViewer),
  125. typeof(ScrollContentPresenter),
  126. typeof(ItemsPresenter),
  127. typeof(StackPanel),
  128. typeof(TextBlock),
  129. },
  130. types);
  131. Assert.Equal(
  132. new object[]
  133. {
  134. target,
  135. target,
  136. scrollViewer,
  137. target,
  138. target,
  139. null
  140. },
  141. templatedParents);
  142. }
  143. private static IControl ItemsControlTemplate(ItemsControl control)
  144. {
  145. return new Border
  146. {
  147. Child = new ScrollViewer
  148. {
  149. Template = new ControlTemplate<ScrollViewer>(ScrollViewerTemplate),
  150. Content = new ItemsPresenter
  151. {
  152. Name = "itemsPresenter",
  153. [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty],
  154. [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty],
  155. }
  156. }
  157. };
  158. }
  159. private static Control ScrollViewerTemplate(ScrollViewer control)
  160. {
  161. var result = new ScrollContentPresenter
  162. {
  163. Name = "contentPresenter",
  164. [~ContentPresenter.ContentProperty] = control[~ContentControl.ContentProperty],
  165. };
  166. return result;
  167. }
  168. private class ApplyTemplateTracker : Control
  169. {
  170. public List<Tuple<IVisual, ILogical>> Invocations { get; } = new List<Tuple<IVisual, ILogical>>();
  171. public override void ApplyTemplate()
  172. {
  173. base.ApplyTemplate();
  174. Invocations.Add(Tuple.Create(this.GetVisualParent(), this.GetLogicalParent()));
  175. }
  176. }
  177. }
  178. }