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);
}
}
}
}