using System; using System.Collections.Generic; using System.Windows; namespace Blois.Utils { public enum RoutingStrategy { Tunnel, Bubble, Direct, } /// /// Half-implemented extensible routed event system. /// Declare a routed event with the syntax such as: /// /// public static readonly BubblingEvent ContextMenuEvent = new BubblingEvent("ContextMenuEventArgs", RoutingStrategy.Bubble); /// /// /// Register a type handler for the event: /// /// static Page() { /// ContextMenuGenerator.ContextMenuEvent.RegisterClassHandler(typeof(Page), Page.HandleContextMenuEvent, false); /// } /// /// /// public class BubblingEvent where T : BubblingEventArgs { Dictionary> registeredTypes = new Dictionary>(); public BubblingEvent(string name, RoutingStrategy routingStrategy) { this.Name = name; this.RoutingStrategy = routingStrategy; } public string Name { get; private set; } public RoutingStrategy RoutingStrategy { get; private set; } public void RegisterClassHandler(Type classType, EventHandler handler) { this.RegisterClassHandler(classType, handler, false); } public void RegisterClassHandler(Type classType, EventHandler handler, bool handledEventsToo) { if (!registeredTypes.ContainsKey(classType)) { registeredTypes[classType] = new BubblingEventRegistration(classType, handler, handledEventsToo); } } public void RaiseEvent(T evt, FrameworkElement element) { switch (this.RoutingStrategy) { case RoutingStrategy.Bubble: this.RaiseBubblingEvent(evt, element); break; case RoutingStrategy.Tunnel: this.RaiseTunnelingEvent(evt, element); break; case RoutingStrategy.Direct: this.RaiseDirectEvent(evt, element); break; } } private void RaiseBubblingEvent(T args, FrameworkElement element) { IList> delegates = this.GetDelegates(element, true); for (int i = 0; i < delegates.Count; ++i) delegates[i].Invoke(args); } private void RaiseTunnelingEvent(T args, FrameworkElement element) { IList> delegates = this.GetDelegates(element, true); for (int i = delegates.Count - 1; i >= 0; --i) delegates[i].Invoke(args); } private void RaiseDirectEvent(T args, FrameworkElement element) { IList> delegates = this.GetDelegates(element, false); for (int i = delegates.Count - 1; i >= 0; --i) delegates[i].Invoke(args); } private IList> GetDelegates(FrameworkElement element, bool walkTree) { List> delegates = new List>(); while (element != null) { Type classType = element.GetType(); while (classType != typeof(object) && classType != null) { BubblingEventRegistration registration; if (this.registeredTypes.TryGetValue(classType, out registration)) delegates.Add(new BubblingEventDelegate(element, registration)); classType = classType.BaseType; } element = element.Parent as FrameworkElement; if (!walkTree) break; } return delegates; } } public delegate void BubblingEventHandler(object sender, T args) where T : BubblingEventArgs; public class BubblingEventArgs : EventArgs { public BubblingEventArgs(object source) { this.Source = source; } public object Source { get; private set; } public bool Handled { get; set; } } public class BubblingEventRegistration where T : BubblingEventArgs { public BubblingEventRegistration(Type classType, EventHandler handler, bool handledEvents) { this.ClassType = classType; this.Handler = handler; this.HandledEvents = handledEvents; } public Type ClassType { get; set; } public EventHandler Handler { get; set; } public bool HandledEvents { get; set; } } public class BubblingEventDelegate where T : BubblingEventArgs { public BubblingEventDelegate(object source, BubblingEventRegistration registration) { this.Source = source; this.EventRegistration = registration; } public BubblingEventRegistration EventRegistration { get; set; } public object Source { get; set; } public void Invoke(T args) { if (!args.Handled || this.EventRegistration.HandledEvents) { this.EventRegistration.Handler(this.Source, args); } } } }