PopupRootTests.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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();
  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();
  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 target = new TemplatedControlWithPopup
  41. {
  42. PopupContent = new Canvas(),
  43. };
  44. var root = new TestRoot { Child = target };
  45. target.ApplyTemplate();
  46. target.Popup.Open();
  47. Assert.Equal(target.Popup, ((IStyleHost)target.Popup.PopupRoot).StylingParent);
  48. }
  49. }
  50. [Fact]
  51. public void Attaching_PopupRoot_To_Parent_Logical_Tree_Raises_DetachedFromLogicalTree_And_AttachedToLogicalTree()
  52. {
  53. using (UnitTestApplication.Start(TestServices.StyledWindow))
  54. {
  55. var child = new Decorator();
  56. var target = CreateTarget();
  57. var window = new Window();
  58. var detachedCount = 0;
  59. var attachedCount = 0;
  60. target.Content = child;
  61. target.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  62. child.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  63. target.AttachedToLogicalTree += (s, e) => ++attachedCount;
  64. child.AttachedToLogicalTree += (s, e) => ++attachedCount;
  65. ((ISetLogicalParent)target).SetParent(window);
  66. Assert.Equal(2, detachedCount);
  67. Assert.Equal(2, attachedCount);
  68. }
  69. }
  70. [Fact]
  71. public void Detaching_PopupRoot_From_Parent_Logical_Tree_Raises_DetachedFromLogicalTree_And_AttachedToLogicalTree()
  72. {
  73. using (UnitTestApplication.Start(TestServices.StyledWindow))
  74. {
  75. var child = new Decorator();
  76. var target = CreateTarget();
  77. var window = new Window();
  78. var detachedCount = 0;
  79. var attachedCount = 0;
  80. target.Content = child;
  81. ((ISetLogicalParent)target).SetParent(window);
  82. target.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  83. child.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  84. target.AttachedToLogicalTree += (s, e) => ++attachedCount;
  85. child.AttachedToLogicalTree += (s, e) => ++attachedCount;
  86. ((ISetLogicalParent)target).SetParent(null);
  87. // Despite being detached from the parent logical tree, we're still attached to a
  88. // logical tree as PopupRoot itself is a logical tree root.
  89. Assert.True(((ILogical)target).IsAttachedToLogicalTree);
  90. Assert.True(((ILogical)child).IsAttachedToLogicalTree);
  91. Assert.Equal(2, detachedCount);
  92. Assert.Equal(2, attachedCount);
  93. }
  94. }
  95. [Fact]
  96. public void Clearing_Content_Of_Popup_In_ControlTemplate_Doesnt_Crash()
  97. {
  98. using (UnitTestApplication.Start(TestServices.StyledWindow))
  99. {
  100. var target = new TemplatedControlWithPopup
  101. {
  102. PopupContent = new Canvas(),
  103. };
  104. var root = new TestRoot { Child = target };
  105. target.ApplyTemplate();
  106. target.Popup.Open();
  107. target.PopupContent = null;
  108. }
  109. }
  110. private PopupRoot CreateTarget()
  111. {
  112. var result = new PopupRoot
  113. {
  114. Template = new FuncControlTemplate<PopupRoot>((parent, scope) =>
  115. new ContentPresenter
  116. {
  117. Name = "PART_ContentPresenter",
  118. [!ContentPresenter.ContentProperty] = parent[!PopupRoot.ContentProperty],
  119. }.RegisterInNameScope(scope)),
  120. };
  121. result.ApplyTemplate();
  122. return result;
  123. }
  124. private class TemplatedControlWithPopup : TemplatedControl
  125. {
  126. public static readonly AvaloniaProperty<Control> PopupContentProperty =
  127. AvaloniaProperty.Register<TemplatedControlWithPopup, Control>(nameof(PopupContent));
  128. public TemplatedControlWithPopup()
  129. {
  130. Template = new FuncControlTemplate<TemplatedControlWithPopup>((parent, _) =>
  131. new Popup
  132. {
  133. [!Popup.ChildProperty] = parent[!TemplatedControlWithPopup.PopupContentProperty],
  134. });
  135. }
  136. public Popup Popup { get; private set; }
  137. public Control PopupContent
  138. {
  139. get => GetValue(PopupContentProperty);
  140. set => SetValue(PopupContentProperty, value);
  141. }
  142. protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
  143. {
  144. Popup = (Popup)this.GetVisualChildren().Single();
  145. }
  146. }
  147. }
  148. }