EventTreeNode.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. using System;
  2. using Avalonia.Diagnostics.Models;
  3. using Avalonia.Diagnostics.Views;
  4. using Avalonia.Interactivity;
  5. using Avalonia.Threading;
  6. using Avalonia.VisualTree;
  7. namespace Avalonia.Diagnostics.ViewModels
  8. {
  9. internal class EventTreeNode : EventTreeNodeBase
  10. {
  11. private readonly EventsPageViewModel _parentViewModel;
  12. private bool _isRegistered;
  13. private FiredEvent? _currentEvent;
  14. public EventTreeNode(EventOwnerTreeNode parent, RoutedEvent @event, EventsPageViewModel vm)
  15. : base(parent, @event.Name)
  16. {
  17. Event = @event ?? throw new ArgumentNullException(nameof(@event));
  18. _parentViewModel = vm ?? throw new ArgumentNullException(nameof(vm));
  19. }
  20. public RoutedEvent Event { get; }
  21. public override bool? IsEnabled
  22. {
  23. get => base.IsEnabled;
  24. set
  25. {
  26. if (base.IsEnabled != value)
  27. {
  28. base.IsEnabled = value;
  29. UpdateTracker();
  30. if (Parent != null && _updateParent)
  31. {
  32. try
  33. {
  34. Parent._updateChildren = false;
  35. Parent.UpdateChecked();
  36. }
  37. finally
  38. {
  39. Parent._updateChildren = true;
  40. }
  41. }
  42. }
  43. }
  44. }
  45. private void UpdateTracker()
  46. {
  47. if (IsEnabled.GetValueOrDefault() && !_isRegistered)
  48. {
  49. var allRoutes = RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble;
  50. // FIXME: This leaks event handlers.
  51. Event.AddClassHandler(typeof(object), HandleEvent, allRoutes, handledEventsToo: true);
  52. Event.RouteFinished.Subscribe(HandleRouteFinished);
  53. _isRegistered = true;
  54. }
  55. }
  56. private void HandleEvent(object? sender, RoutedEventArgs e)
  57. {
  58. if (!_isRegistered || IsEnabled == false)
  59. return;
  60. if (sender is IVisual v && BelongsToDevTool(v))
  61. return;
  62. var s = sender!;
  63. var handled = e.Handled;
  64. var route = e.Route;
  65. void handler()
  66. {
  67. if (_currentEvent == null || !_currentEvent.IsPartOfSameEventChain(e))
  68. {
  69. _currentEvent = new FiredEvent(e, new EventChainLink(s, handled, route));
  70. _parentViewModel.RecordedEvents.Add(_currentEvent);
  71. while (_parentViewModel.RecordedEvents.Count > 100)
  72. _parentViewModel.RecordedEvents.RemoveAt(0);
  73. }
  74. else
  75. {
  76. _currentEvent.AddToChain(new EventChainLink(s, handled, route));
  77. }
  78. };
  79. if (!Dispatcher.UIThread.CheckAccess())
  80. Dispatcher.UIThread.Post(handler);
  81. else
  82. handler();
  83. }
  84. private void HandleRouteFinished(RoutedEventArgs e)
  85. {
  86. if (!_isRegistered || IsEnabled == false)
  87. return;
  88. if (e.Source is IVisual v && BelongsToDevTool(v))
  89. return;
  90. var s = e.Source;
  91. var handled = e.Handled;
  92. var route = e.Route;
  93. void handler()
  94. {
  95. if (_currentEvent != null && handled)
  96. {
  97. var linkIndex = _currentEvent.EventChain.Count - 1;
  98. var link = _currentEvent.EventChain[linkIndex];
  99. link.Handled = true;
  100. _currentEvent.HandledBy = link;
  101. }
  102. }
  103. if (!Dispatcher.UIThread.CheckAccess())
  104. Dispatcher.UIThread.Post(handler);
  105. else
  106. handler();
  107. }
  108. private static bool BelongsToDevTool(IVisual v)
  109. {
  110. var current = v;
  111. while (current != null)
  112. {
  113. if (current is MainView || current is MainWindow)
  114. {
  115. return true;
  116. }
  117. current = current.VisualParent;
  118. }
  119. return false;
  120. }
  121. }
  122. }