NavigationPageStackPage.xaml.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using System.Threading.Tasks;
  2. using Avalonia.Controls;
  3. using Avalonia;
  4. using Avalonia.Interactivity;
  5. using Avalonia.Layout;
  6. using Avalonia.Media;
  7. namespace ControlCatalog.Pages
  8. {
  9. public partial class NavigationPageStackPage : UserControl
  10. {
  11. private bool _initialized;
  12. private int _pageCount;
  13. public NavigationPageStackPage()
  14. {
  15. InitializeComponent();
  16. Loaded += OnLoaded;
  17. }
  18. private async void OnLoaded(object? sender, RoutedEventArgs e)
  19. {
  20. if (_initialized)
  21. return;
  22. _initialized = true;
  23. DemoNav.Pushed += (s, ev) => RefreshStack();
  24. DemoNav.Popped += (s, ev) => RefreshStack();
  25. DemoNav.PoppedToRoot += (s, ev) => RefreshStack();
  26. DemoNav.PageInserted += (s, ev) => RefreshStack();
  27. DemoNav.PageRemoved += (s, ev) => RefreshStack();
  28. _pageCount++;
  29. await DemoNav.PushAsync(NavigationDemoHelper.MakePage("Home", $"Stack position #{_pageCount}", _pageCount), null);
  30. // RefreshStack is called via the Pushed event above.
  31. }
  32. private async void OnPush(object? sender, RoutedEventArgs e)
  33. {
  34. _pageCount++;
  35. await DemoNav.PushAsync(NavigationDemoHelper.MakePage($"Page {_pageCount}", $"Stack position #{_pageCount}", _pageCount));
  36. }
  37. private void OnInsert(object? sender, RoutedEventArgs e)
  38. {
  39. var current = DemoNav.CurrentPage;
  40. if (current == null || DemoNav.StackDepth <= 1)
  41. return;
  42. _pageCount++;
  43. var inserted = NavigationDemoHelper.MakePage($"Inserted {_pageCount}", $"Stack position #{_pageCount}", _pageCount);
  44. DemoNav.InsertPage(inserted, current);
  45. RefreshStack();
  46. }
  47. private void RefreshStack()
  48. {
  49. var stack = DemoNav.NavigationStack;
  50. var depth = stack.Count;
  51. var current = DemoNav.CurrentPage;
  52. DepthLabel.Text = $"depth: {depth}";
  53. StackDisplay.Children.Clear();
  54. // Render from top (current) down to root.
  55. for (int i = depth - 1; i >= 0; i--)
  56. {
  57. var page = stack[i];
  58. var isCurrent = ReferenceEquals(page, current);
  59. var isRoot = i == 0;
  60. StackDisplay.Children.Add(BuildStackEntry(page, i + 1, isCurrent, isRoot));
  61. }
  62. }
  63. private Border BuildStackEntry(Page page, int position, bool isCurrent, bool isRoot)
  64. {
  65. var background = NavigationDemoHelper.GetPageBrush(position - 1);
  66. var badge = new Border
  67. {
  68. Width = 24,
  69. Height = 24,
  70. CornerRadius = new CornerRadius(12),
  71. Background = background,
  72. VerticalAlignment = VerticalAlignment.Center,
  73. Child = new TextBlock
  74. {
  75. Text = position.ToString(),
  76. FontSize = 11,
  77. FontWeight = FontWeight.SemiBold,
  78. HorizontalAlignment = HorizontalAlignment.Center,
  79. VerticalAlignment = VerticalAlignment.Center,
  80. }
  81. };
  82. var title = new TextBlock
  83. {
  84. Text = page.Header?.ToString() ?? "(untitled)",
  85. FontWeight = isCurrent ? FontWeight.SemiBold : FontWeight.Normal,
  86. VerticalAlignment = VerticalAlignment.Center,
  87. TextTrimming = TextTrimming.CharacterEllipsis,
  88. Margin = new Thickness(6, 0, 0, 0),
  89. };
  90. string? badgeText = isCurrent ? "current" : (isRoot ? "root" : null);
  91. var badgeLabel = new TextBlock
  92. {
  93. Text = badgeText,
  94. FontSize = 10,
  95. Opacity = 0.5,
  96. VerticalAlignment = VerticalAlignment.Center,
  97. IsVisible = badgeText != null,
  98. Margin = new Thickness(4, 0, 0, 0),
  99. };
  100. // Remove button (disabled when it is the only page in the stack)
  101. var removeBtn = new Button
  102. {
  103. Content = "Remove",
  104. FontSize = 11,
  105. Padding = new Thickness(6, 2),
  106. VerticalAlignment = VerticalAlignment.Center,
  107. IsEnabled = !(isRoot && DemoNav.StackDepth == 1),
  108. };
  109. removeBtn.Click += (_, _) =>
  110. {
  111. DemoNav.RemovePage(page);
  112. RefreshStack();
  113. };
  114. // Insert-before button (not shown for current page — use the dedicated button instead)
  115. var insertBtn = new Button
  116. {
  117. Content = "Insert \u2191",
  118. FontSize = 11,
  119. Padding = new Thickness(6, 2),
  120. VerticalAlignment = VerticalAlignment.Center,
  121. IsVisible = !isCurrent,
  122. };
  123. ToolTip.SetTip(insertBtn, $"Insert a new page before \"{page.Header}\"");
  124. insertBtn.Click += (_, _) =>
  125. {
  126. _pageCount++;
  127. var inserted = NavigationDemoHelper.MakePage($"Inserted {_pageCount}", $"Stack position #{_pageCount}", _pageCount);
  128. DemoNav.InsertPage(inserted, page);
  129. RefreshStack();
  130. };
  131. var buttonsPanel = new StackPanel
  132. {
  133. Orientation = Orientation.Horizontal,
  134. Spacing = 4,
  135. VerticalAlignment = VerticalAlignment.Center,
  136. };
  137. buttonsPanel.Children.Add(removeBtn);
  138. buttonsPanel.Children.Add(insertBtn);
  139. var titleRow = new DockPanel { LastChildFill = true };
  140. DockPanel.SetDock(buttonsPanel, Dock.Right);
  141. titleRow.Children.Add(buttonsPanel);
  142. titleRow.Children.Add(badge);
  143. titleRow.Children.Add(title);
  144. titleRow.Children.Add(badgeLabel);
  145. return new Border
  146. {
  147. BorderBrush = new SolidColorBrush(isCurrent
  148. ? Color.Parse("#0078D4")
  149. : Color.Parse("#CCCCCC")),
  150. BorderThickness = new Thickness(isCurrent ? 2 : 1),
  151. CornerRadius = new CornerRadius(6),
  152. Padding = new Thickness(8, 6),
  153. Child = titleRow,
  154. };
  155. }
  156. }
  157. }