PopupRootTests.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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.Linq;
  5. using Avalonia.Controls.Presenters;
  6. using Avalonia.Controls.Primitives;
  7. using Avalonia.Controls.Templates;
  8. using Avalonia.LogicalTree;
  9. using Avalonia.Styling;
  10. using Avalonia.UnitTests;
  11. using Avalonia.VisualTree;
  12. using Xunit;
  13. namespace Avalonia.Controls.UnitTests.Primitives
  14. {
  15. public class PopupRootTests
  16. {
  17. [Fact]
  18. public void PopupRoot_IsAttachedToLogicalTree_Is_True()
  19. {
  20. using (UnitTestApplication.Start(TestServices.StyledWindow))
  21. {
  22. var target = CreateTarget(new Window());
  23. Assert.True(((ILogical)target).IsAttachedToLogicalTree);
  24. }
  25. }
  26. [Fact]
  27. public void Templated_Child_IsAttachedToLogicalTree_Is_True()
  28. {
  29. using (UnitTestApplication.Start(TestServices.StyledWindow))
  30. {
  31. var target = CreateTarget(new Window());
  32. Assert.True(target.Presenter.IsAttachedToLogicalTree);
  33. }
  34. }
  35. [Fact]
  36. public void PopupRoot_StylingParent_Is_Popup()
  37. {
  38. using (UnitTestApplication.Start(TestServices.StyledWindow))
  39. {
  40. var window = new Window();
  41. var target = new TemplatedControlWithPopup
  42. {
  43. PopupContent = new Canvas(),
  44. };
  45. window.Content = target;
  46. window.ApplyTemplate();
  47. window.Presenter.ApplyTemplate();
  48. target.ApplyTemplate();
  49. target.Popup.Open();
  50. Assert.Equal(target.Popup, ((IStyleHost)target.Popup.Host).StylingParent);
  51. }
  52. }
  53. [Fact]
  54. public void PopupRoot_Should_Have_Template_Applied()
  55. {
  56. using (UnitTestApplication.Start(TestServices.StyledWindow))
  57. {
  58. var window = new Window();
  59. var target = new Popup {PlacementMode = PlacementMode.Pointer};
  60. var child = new Control();
  61. window.Content = target;
  62. window.ApplyTemplate();
  63. target.Open();
  64. Assert.Single(((Visual)target.Host).GetVisualChildren());
  65. var templatedChild = ((Visual)target.Host).GetVisualChildren().Single();
  66. Assert.IsType<VisualLayerManager>(templatedChild);
  67. var contentPresenter = templatedChild.VisualChildren.Single();
  68. Assert.IsType<ContentPresenter>(contentPresenter);
  69. Assert.Equal((PopupRoot)target.Host, ((IControl)templatedChild).TemplatedParent);
  70. Assert.Equal((PopupRoot)target.Host, ((IControl)contentPresenter).TemplatedParent);
  71. }
  72. }
  73. [Fact]
  74. public void PopupRoot_Should_Have_Null_VisualParent()
  75. {
  76. using (UnitTestApplication.Start(TestServices.StyledWindow))
  77. {
  78. var target = new Popup() {PlacementTarget = new Window()};
  79. target.Open();
  80. Assert.Null(((Visual)target.Host).GetVisualParent());
  81. }
  82. }
  83. [Fact]
  84. public void Attaching_PopupRoot_To_Parent_Logical_Tree_Raises_DetachedFromLogicalTree_And_AttachedToLogicalTree()
  85. {
  86. using (UnitTestApplication.Start(TestServices.StyledWindow))
  87. {
  88. var child = new Decorator();
  89. var window = new Window();
  90. var target = CreateTarget(window);
  91. var detachedCount = 0;
  92. var attachedCount = 0;
  93. target.Content = child;
  94. target.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  95. child.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  96. target.AttachedToLogicalTree += (s, e) => ++attachedCount;
  97. child.AttachedToLogicalTree += (s, e) => ++attachedCount;
  98. ((ISetLogicalParent)target).SetParent(window);
  99. Assert.Equal(2, detachedCount);
  100. Assert.Equal(2, attachedCount);
  101. }
  102. }
  103. [Fact]
  104. public void Detaching_PopupRoot_From_Parent_Logical_Tree_Raises_DetachedFromLogicalTree_And_AttachedToLogicalTree()
  105. {
  106. using (UnitTestApplication.Start(TestServices.StyledWindow))
  107. {
  108. var child = new Decorator();
  109. var window = new Window();
  110. var target = CreateTarget(window);
  111. var detachedCount = 0;
  112. var attachedCount = 0;
  113. target.Content = child;
  114. ((ISetLogicalParent)target).SetParent(window);
  115. target.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  116. child.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  117. target.AttachedToLogicalTree += (s, e) => ++attachedCount;
  118. child.AttachedToLogicalTree += (s, e) => ++attachedCount;
  119. ((ISetLogicalParent)target).SetParent(null);
  120. // Despite being detached from the parent logical tree, we're still attached to a
  121. // logical tree as PopupRoot itself is a logical tree root.
  122. Assert.True(((ILogical)target).IsAttachedToLogicalTree);
  123. Assert.True(((ILogical)child).IsAttachedToLogicalTree);
  124. Assert.Equal(2, detachedCount);
  125. Assert.Equal(2, attachedCount);
  126. }
  127. }
  128. [Fact]
  129. public void Clearing_Content_Of_Popup_In_ControlTemplate_Doesnt_Crash()
  130. {
  131. using (UnitTestApplication.Start(TestServices.StyledWindow))
  132. {
  133. var window = new Window();
  134. var target = new TemplatedControlWithPopup
  135. {
  136. PopupContent = new Canvas(),
  137. };
  138. window.Content = target;
  139. window.ApplyTemplate();
  140. window.Presenter.ApplyTemplate();
  141. target.ApplyTemplate();
  142. target.Popup.Open();
  143. target.PopupContent = null;
  144. }
  145. }
  146. private PopupRoot CreateTarget(TopLevel popupParent)
  147. {
  148. var result = new PopupRoot(popupParent, popupParent.PlatformImpl.CreatePopup())
  149. {
  150. Template = new FuncControlTemplate<PopupRoot>((parent, scope) =>
  151. new ContentPresenter
  152. {
  153. Name = "PART_ContentPresenter",
  154. [!ContentPresenter.ContentProperty] = parent[!PopupRoot.ContentProperty],
  155. }.RegisterInNameScope(scope)),
  156. };
  157. result.ApplyTemplate();
  158. return result;
  159. }
  160. private class TemplatedControlWithPopup : TemplatedControl
  161. {
  162. public static readonly AvaloniaProperty<Control> PopupContentProperty =
  163. AvaloniaProperty.Register<TemplatedControlWithPopup, Control>(nameof(PopupContent));
  164. public TemplatedControlWithPopup()
  165. {
  166. Template = new FuncControlTemplate<TemplatedControlWithPopup>((parent, _) =>
  167. new Popup
  168. {
  169. [!Popup.ChildProperty] = parent[!TemplatedControlWithPopup.PopupContentProperty],
  170. PlacementTarget = parent
  171. });
  172. }
  173. public Popup Popup { get; private set; }
  174. public Control PopupContent
  175. {
  176. get => GetValue(PopupContentProperty);
  177. set => SetValue(PopupContentProperty, value);
  178. }
  179. protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
  180. {
  181. Popup = (Popup)this.GetVisualChildren().Single();
  182. }
  183. }
  184. }
  185. }