PopupRootTests.cs 7.8 KB

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