PopupRootTests.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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.UnitTests;
  10. using Avalonia.VisualTree;
  11. using Xunit;
  12. namespace Avalonia.Controls.UnitTests.Primitives
  13. {
  14. public class PopupRootTests
  15. {
  16. [Fact]
  17. public void PopupRoot_IsAttachedToLogicalTree_Is_True()
  18. {
  19. using (UnitTestApplication.Start(TestServices.StyledWindow))
  20. {
  21. var target = CreateTarget();
  22. Assert.True(((ILogical)target).IsAttachedToLogicalTree);
  23. }
  24. }
  25. [Fact]
  26. public void Templated_Child_IsAttachedToLogicalTree_Is_True()
  27. {
  28. using (UnitTestApplication.Start(TestServices.StyledWindow))
  29. {
  30. var target = CreateTarget();
  31. Assert.True(target.Presenter.IsAttachedToLogicalTree);
  32. }
  33. }
  34. [Fact]
  35. public void Attaching_PopupRoot_To_Parent_Logical_Tree_Raises_DetachedFromLogicalTree_And_AttachedToLogicalTree()
  36. {
  37. using (UnitTestApplication.Start(TestServices.StyledWindow))
  38. {
  39. var child = new Decorator();
  40. var target = CreateTarget();
  41. var window = new Window();
  42. var detachedCount = 0;
  43. var attachedCount = 0;
  44. target.Content = child;
  45. target.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  46. child.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  47. target.AttachedToLogicalTree += (s, e) => ++attachedCount;
  48. child.AttachedToLogicalTree += (s, e) => ++attachedCount;
  49. ((ISetLogicalParent)target).SetParent(window);
  50. Assert.Equal(2, detachedCount);
  51. Assert.Equal(2, attachedCount);
  52. }
  53. }
  54. [Fact]
  55. public void Detaching_PopupRoot_From_Parent_Logical_Tree_Raises_DetachedFromLogicalTree_And_AttachedToLogicalTree()
  56. {
  57. using (UnitTestApplication.Start(TestServices.StyledWindow))
  58. {
  59. var child = new Decorator();
  60. var target = CreateTarget();
  61. var window = new Window();
  62. var detachedCount = 0;
  63. var attachedCount = 0;
  64. target.Content = child;
  65. ((ISetLogicalParent)target).SetParent(window);
  66. target.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  67. child.DetachedFromLogicalTree += (s, e) => ++detachedCount;
  68. target.AttachedToLogicalTree += (s, e) => ++attachedCount;
  69. child.AttachedToLogicalTree += (s, e) => ++attachedCount;
  70. ((ISetLogicalParent)target).SetParent(null);
  71. // Despite being detached from the parent logical tree, we're still attached to a
  72. // logical tree as PopupRoot itself is a logical tree root.
  73. Assert.True(((ILogical)target).IsAttachedToLogicalTree);
  74. Assert.True(((ILogical)child).IsAttachedToLogicalTree);
  75. Assert.Equal(2, detachedCount);
  76. Assert.Equal(2, attachedCount);
  77. }
  78. }
  79. [Fact]
  80. public void Clearing_Content_Of_Popup_In_ControlTemplate_Doesnt_Crash()
  81. {
  82. using (UnitTestApplication.Start(TestServices.StyledWindow))
  83. {
  84. var target = new TemplatedControlWithPopup
  85. {
  86. PopupContent = new Canvas(),
  87. };
  88. var root = new TestRoot { Child = target };
  89. target.ApplyTemplate();
  90. target.Popup.Open();
  91. target.PopupContent = null;
  92. }
  93. }
  94. private PopupRoot CreateTarget()
  95. {
  96. var result = new PopupRoot
  97. {
  98. Template = new FuncControlTemplate<PopupRoot>(parent =>
  99. new ContentPresenter
  100. {
  101. Name = "PART_ContentPresenter",
  102. [!ContentPresenter.ContentProperty] = parent[!PopupRoot.ContentProperty],
  103. }),
  104. };
  105. result.ApplyTemplate();
  106. return result;
  107. }
  108. private class TemplatedControlWithPopup : TemplatedControl
  109. {
  110. public static readonly AvaloniaProperty<Control> PopupContentProperty =
  111. AvaloniaProperty.Register<TemplatedControlWithPopup, Control>(nameof(PopupContent));
  112. public TemplatedControlWithPopup()
  113. {
  114. Template = new FuncControlTemplate<TemplatedControlWithPopup>(parent =>
  115. new Popup
  116. {
  117. [!Popup.ChildProperty] = parent[!TemplatedControlWithPopup.PopupContentProperty],
  118. });
  119. }
  120. public Popup Popup { get; private set; }
  121. public Control PopupContent
  122. {
  123. get => GetValue(PopupContentProperty);
  124. set => SetValue(PopupContentProperty, value);
  125. }
  126. protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
  127. {
  128. Popup = (Popup)this.GetVisualChildren().Single();
  129. }
  130. }
  131. }
  132. }