RoutedEvent.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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.Reactive.Subjects;
  5. namespace Avalonia.Interactivity
  6. {
  7. [Flags]
  8. public enum RoutingStrategies
  9. {
  10. Direct = 0x01,
  11. Tunnel = 0x02,
  12. Bubble = 0x04,
  13. }
  14. public class RoutedEvent
  15. {
  16. private readonly Subject<(object, RoutedEventArgs)> _raised = new Subject<(object, RoutedEventArgs)>();
  17. private readonly Subject<RoutedEventArgs> _routeFinished = new Subject<RoutedEventArgs>();
  18. public RoutedEvent(
  19. string name,
  20. RoutingStrategies routingStrategies,
  21. Type eventArgsType,
  22. Type ownerType)
  23. {
  24. name = name ?? throw new ArgumentNullException(nameof(name));
  25. eventArgsType = eventArgsType ?? throw new ArgumentNullException(nameof(name));
  26. ownerType = ownerType ?? throw new ArgumentNullException(nameof(name));
  27. if (!typeof(RoutedEventArgs).IsAssignableFrom(eventArgsType))
  28. {
  29. throw new InvalidCastException("eventArgsType must be derived from RoutedEventArgs.");
  30. }
  31. EventArgsType = eventArgsType;
  32. Name = name;
  33. OwnerType = ownerType;
  34. RoutingStrategies = routingStrategies;
  35. }
  36. public Type EventArgsType { get; }
  37. public string Name { get; }
  38. public Type OwnerType { get; }
  39. public RoutingStrategies RoutingStrategies { get; }
  40. public bool HasRaisedSubscriptions => _raised.HasObservers;
  41. public IObservable<(object, RoutedEventArgs)> Raised => _raised;
  42. public IObservable<RoutedEventArgs> RouteFinished => _routeFinished;
  43. public static RoutedEvent<TEventArgs> Register<TOwner, TEventArgs>(
  44. string name,
  45. RoutingStrategies routingStrategy)
  46. where TEventArgs : RoutedEventArgs
  47. {
  48. name = name ?? throw new ArgumentNullException(nameof(name));
  49. var routedEvent = new RoutedEvent<TEventArgs>(name, routingStrategy, typeof(TOwner));
  50. RoutedEventRegistry.Instance.Register(typeof(TOwner), routedEvent);
  51. return routedEvent;
  52. }
  53. public static RoutedEvent<TEventArgs> Register<TEventArgs>(
  54. string name,
  55. RoutingStrategies routingStrategy,
  56. Type ownerType)
  57. where TEventArgs : RoutedEventArgs
  58. {
  59. name = name ?? throw new ArgumentNullException(nameof(name));
  60. var routedEvent = new RoutedEvent<TEventArgs>(name, routingStrategy, ownerType);
  61. RoutedEventRegistry.Instance.Register(ownerType, routedEvent);
  62. return routedEvent;
  63. }
  64. public IDisposable AddClassHandler(
  65. Type targetType,
  66. EventHandler<RoutedEventArgs> handler,
  67. RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
  68. bool handledEventsToo = false)
  69. {
  70. return Raised.Subscribe(args =>
  71. {
  72. (object sender, RoutedEventArgs e) = args;
  73. if (targetType.IsInstanceOfType(sender) &&
  74. (e.Route == RoutingStrategies.Direct || (e.Route & routes) != 0) &&
  75. (!e.Handled || handledEventsToo))
  76. {
  77. handler(sender, e);
  78. }
  79. });
  80. }
  81. internal void InvokeRaised(object sender, RoutedEventArgs e)
  82. {
  83. _raised.OnNext((sender, e));
  84. }
  85. internal void InvokeRouteFinished(RoutedEventArgs e)
  86. {
  87. _routeFinished.OnNext(e);
  88. }
  89. }
  90. public class RoutedEvent<TEventArgs> : RoutedEvent
  91. where TEventArgs : RoutedEventArgs
  92. {
  93. public RoutedEvent(string name, RoutingStrategies routingStrategies, Type ownerType)
  94. : base(name, routingStrategies, typeof(TEventArgs), ownerType)
  95. {
  96. }
  97. [Obsolete("Use overload taking Action<TTarget, TEventArgs>.")]
  98. public IDisposable AddClassHandler<TTarget>(
  99. Func<TTarget, Action<TEventArgs>> handler,
  100. RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
  101. bool handledEventsToo = false)
  102. where TTarget : class, IInteractive
  103. {
  104. void Adapter(object sender, RoutedEventArgs e)
  105. {
  106. if (sender is TTarget target && e is TEventArgs args)
  107. {
  108. handler(target)(args);
  109. }
  110. }
  111. return AddClassHandler(typeof(TTarget), Adapter, routes, handledEventsToo);
  112. }
  113. public IDisposable AddClassHandler<TTarget>(
  114. Action<TTarget, TEventArgs> handler,
  115. RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
  116. bool handledEventsToo = false) where TTarget : class, IInteractive
  117. {
  118. void Adapter(object sender, RoutedEventArgs e)
  119. {
  120. if (sender is TTarget target && e is TEventArgs args)
  121. {
  122. handler(target, args);
  123. }
  124. }
  125. return AddClassHandler(typeof(TTarget), Adapter, routes, handledEventsToo);
  126. }
  127. }
  128. }