// ----------------------------------------------------------------------- // // Copyright 2014 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Interactivity { using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; [Flags] public enum RoutingStrategies { Direct = 0x01, Tunnel = 0x02, Bubble = 0x04, } public class RoutedEvent { private List subscriptions = new List(); public RoutedEvent( string name, RoutingStrategies routingStrategies, Type eventArgsType, Type ownerType) { Contract.Requires(name != null); Contract.Requires(eventArgsType != null); Contract.Requires(ownerType != null); Contract.Requires(typeof(RoutedEventArgs).GetTypeInfo().IsAssignableFrom(eventArgsType.GetTypeInfo())); this.EventArgsType = eventArgsType; this.Name = name; this.OwnerType = ownerType; this.RoutingStrategies = routingStrategies; } public Type EventArgsType { get; private set; } public string Name { get; private set; } public Type OwnerType { get; private set; } public RoutingStrategies RoutingStrategies { get; private set; } public static RoutedEvent Register( string name, RoutingStrategies routingStrategy) where TEventArgs : RoutedEventArgs { Contract.Requires(name != null); return new RoutedEvent(name, routingStrategy, typeof(TOwner)); } public static RoutedEvent Register( string name, RoutingStrategies routingStrategy, Type ownerType) where TEventArgs : RoutedEventArgs { Contract.Requires(name != null); return new RoutedEvent(name, routingStrategy, ownerType); } public void AddClassHandler(Type type, EventHandler handler, RoutingStrategies routes) { this.subscriptions.Add(new ClassEventSubscription { TargetType = type, Handler = handler, Routes = routes, }); } internal void InvokeClassHandlers(object sender, RoutedEventArgs e) { foreach (var sub in this.subscriptions) { if (sub.TargetType.GetTypeInfo().IsAssignableFrom(sender.GetType().GetTypeInfo()) && ((e.Route == RoutingStrategies.Direct) || (e.Route & sub.Routes) != 0) && (!e.Handled || sub.AlsoIfHandled)) { sub.Handler.DynamicInvoke(sender, e); } } } private class ClassEventSubscription : EventSubscription { public Type TargetType { get; set; } } } public class RoutedEvent : RoutedEvent where TEventArgs : RoutedEventArgs { public RoutedEvent(string name, RoutingStrategies routingStrategies, Type ownerType) : base(name, routingStrategies, typeof(TEventArgs), ownerType) { Contract.Requires(name != null); Contract.Requires(ownerType != null); } public void AddClassHandler( Func> handler, RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble) where TTarget : class { this.AddClassHandler(typeof(TTarget), (s, e) => ClassHandlerAdapter(s, e, handler), routes); } 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); } } } }