diff --git a/src/Perspex.Interactivity/Interactive.cs b/src/Perspex.Interactivity/Interactive.cs index a6bfd0d94c..956b2c2722 100644 --- a/src/Perspex.Interactivity/Interactive.cs +++ b/src/Perspex.Interactivity/Interactive.cs @@ -175,7 +175,7 @@ namespace Perspex.Interactivity { Contract.Requires(e != null); - e.RoutedEvent.InvokeClassHandlers(this, e); + e.RoutedEvent.InvokeRaised(this, e); List subscriptions; diff --git a/src/Perspex.Interactivity/RoutedEvent.cs b/src/Perspex.Interactivity/RoutedEvent.cs index 3fa8f9aaf5..3040c867a4 100644 --- a/src/Perspex.Interactivity/RoutedEvent.cs +++ b/src/Perspex.Interactivity/RoutedEvent.cs @@ -2,8 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; -using System.Collections.Generic; -using System.Linq.Expressions; +using System.Reactive.Subjects; using System.Reflection; using System.Runtime.ExceptionServices; @@ -19,7 +18,7 @@ namespace Perspex.Interactivity public class RoutedEvent { - private readonly List _subscriptions = new List(); + private Subject> _raised = new Subject>(); public RoutedEvent( string name, @@ -62,6 +61,8 @@ namespace Perspex.Interactivity private set; } + public IObservable> Raised => _raised; + public static RoutedEvent Register( string name, RoutingStrategies routingStrategy) @@ -83,27 +84,24 @@ namespace Perspex.Interactivity return new RoutedEvent(name, routingStrategy, ownerType); } - public void AddClassHandler(Type type, EventHandler handler, RoutingStrategies routes) + public IDisposable AddClassHandler( + Type targetType, + EventHandler handler, + RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble, + bool handledEventsToo = false) { - _subscriptions.Add(new ClassEventSubscription + return Raised.Subscribe(args => { - TargetType = type, - Handler = handler, - Routes = routes, - }); - } + var sender = args.Item1; + var e = args.Item2; - internal void InvokeClassHandlers(object sender, RoutedEventArgs e) - { - foreach (var sub in _subscriptions) - { - if (sub.TargetType.GetTypeInfo().IsAssignableFrom(sender.GetType().GetTypeInfo()) && - ((e.Route == RoutingStrategies.Direct) || (e.Route & sub.Routes) != 0) && - (!e.Handled || sub.AlsoIfHandled)) + if (targetType.GetTypeInfo().IsAssignableFrom(sender.GetType().GetTypeInfo()) && + ((e.Route == RoutingStrategies.Direct) || (e.Route & routes) != 0) && + (!e.Handled || handledEventsToo)) { try { - sub.Handler.DynamicInvoke(sender, e); + handler.DynamicInvoke(sender, e); } catch (TargetInvocationException ex) { @@ -111,12 +109,12 @@ namespace Perspex.Interactivity ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } - } + }); } - private class ClassEventSubscription : EventSubscription + internal void InvokeRaised(object sender, RoutedEventArgs e) { - public Type TargetType { get; set; } + _raised.OnNext(Tuple.Create(sender, e)); } } @@ -130,26 +128,24 @@ namespace Perspex.Interactivity Contract.Requires(ownerType != null); } - public void AddClassHandler( + public IDisposable AddClassHandler( Func> handler, - RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble) - where TTarget : class + RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble, + bool handledEventsToo = false) + where TTarget : class, IInteractive { - AddClassHandler(typeof(TTarget), (s, e) => ClassHandlerAdapter(s, e, handler), routes); - } + EventHandler adapter = (sender, e) => + { + var target = sender as TTarget; + var args = e as TEventArgs; - private static void ClassHandlerAdapter( - object sender, - RoutedEventArgs e, - Func> handler) where TTarget : class - { - var target = sender as TTarget; - var args = e as TEventArgs; + if (target != null && args != null) + { + handler(target)(args); + } + }; - if (target != null && args != null) - { - handler(target)(args); - } + return AddClassHandler(typeof(TTarget), adapter, routes, handledEventsToo); } } }