195 lines
6.9 KiB
C#
195 lines
6.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
|
|
|
|
namespace DataPro.Core.EventManager
|
|
{
|
|
/// <summary>
|
|
/// Delegate used by event listeners
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="item"></param>
|
|
public delegate void SubscriberCallbackDelegate<in T>(T item) where T : class;
|
|
|
|
public delegate void DiagnosticCallbackDelegate(EventDiagnosticType eventType, Type t, object eventData, string listener);
|
|
|
|
/// <summary>
|
|
/// Allows components to publish events without knowing who is listening
|
|
/// </summary>
|
|
public static class EventManager
|
|
{
|
|
/// <summary>
|
|
/// Tracks listeners
|
|
/// </summary>
|
|
private static readonly Dictionary<Type, List<object>> SubscriberList = new Dictionary<Type, List<object>>();
|
|
|
|
/// <summary>
|
|
/// Tracks diagnostic listeners
|
|
/// </summary>
|
|
private static readonly List<DiagnosticCallbackDelegate> DiagnosticList = new List<DiagnosticCallbackDelegate>();
|
|
|
|
|
|
/// <summary>
|
|
/// Publish an event
|
|
/// </summary>
|
|
/// <typeparam name="T">type of event</typeparam>
|
|
/// <param name="eventData">event listener</param>
|
|
public static void Publish<T>(T eventData) where T : class
|
|
{
|
|
if (!SubscriberList.ContainsKey(typeof(T))) return;
|
|
|
|
var listeners = SubscriberList[typeof(T)];
|
|
|
|
foreach (var listener in listeners)
|
|
{
|
|
var metaData = listener as EventMetaData<T>;
|
|
if (metaData == null) continue;
|
|
|
|
var triggerCallback = true;
|
|
|
|
if (metaData.EventFilter != null)
|
|
{
|
|
triggerCallback = metaData.EventFilter(eventData);
|
|
}
|
|
|
|
if (triggerCallback)
|
|
{
|
|
metaData.Callback(eventData);
|
|
}
|
|
|
|
SendDiagnosticEvent(EventDiagnosticType.PublishEvent, typeof(T), eventData, metaData.EventFilter != null ? metaData.EventFilter.Method : null);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subscribe to an event
|
|
/// </summary>
|
|
/// <typeparam name="T">type of event</typeparam>
|
|
/// <param name="listener">event listener</param>
|
|
public static void Subscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
|
|
{
|
|
Subscribe(listener, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subscribe to an event
|
|
/// </summary>
|
|
/// <typeparam name="T">type of event</typeparam>
|
|
/// <param name="listener">event listener</param>
|
|
/// <param name="eventFilter">predicate to filter events sent to event listener</param>
|
|
public static void Subscribe<T>(SubscriberCallbackDelegate<T> listener, Predicate<T> eventFilter) where T : class
|
|
{
|
|
if (!SubscriberList.ContainsKey(typeof(T)))
|
|
{
|
|
SubscriberList.Add(typeof(T), new List<object>());
|
|
}
|
|
|
|
var listeners = SubscriberList[typeof(T)];
|
|
|
|
var metaData = new EventMetaData<T> { Callback = listener, EventFilter = eventFilter };
|
|
|
|
listeners.Add(metaData);
|
|
|
|
SendDiagnosticEvent(EventDiagnosticType.AddListener, typeof(T), null, listener.Method);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Allows a subscriber to unsubscribe
|
|
/// </summary>
|
|
/// <typeparam name="T">type of event</typeparam>
|
|
/// <param name="listener">event listener</param>
|
|
public static void UnSubscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
|
|
{
|
|
if (!SubscriberList.ContainsKey(typeof(T))) return;
|
|
|
|
var listeners = SubscriberList[typeof(T)];
|
|
|
|
listeners.RemoveAll(p =>
|
|
{
|
|
var eventMetaData = p as EventMetaData<T>;
|
|
return eventMetaData != null && eventMetaData.Callback == listener;
|
|
});
|
|
|
|
SendDiagnosticEvent(EventDiagnosticType.RemoveListener, typeof(T), null, listener.Method);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears all listeners
|
|
/// </summary>
|
|
public static void Clear()
|
|
{
|
|
SubscriberList.Clear();
|
|
SendDiagnosticEvent(EventDiagnosticType.RemoveListener, null, null, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add diagnostic listener
|
|
/// </summary>
|
|
/// <param name="listener">event listener</param>
|
|
public static void SubscribeToDiagnosticEvents(DiagnosticCallbackDelegate listener)
|
|
{
|
|
DiagnosticList.Add(listener);
|
|
SendDiagnosticEvent(EventDiagnosticType.AddListenerDiagnostic, null, null, listener.Method);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear diagnostic event
|
|
/// </summary>
|
|
/// <param name="listener">listener to unsubscribe</param>
|
|
public static void UnSubscribeToDiagnosticEvents(DiagnosticCallbackDelegate listener)
|
|
{
|
|
DiagnosticList.RemoveAll(p => p == listener);
|
|
SendDiagnosticEvent(EventDiagnosticType.RemoveListenerDiagnostic, null, null, listener.Method);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear all diagnostic events
|
|
/// </summary>
|
|
public static void ClearDiagnosticEvents()
|
|
{
|
|
DiagnosticList.Clear();
|
|
SendDiagnosticEvent(EventDiagnosticType.RemoveListenerDiagnostic, null, null, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends a diagnostic event
|
|
/// </summary>
|
|
/// <param name="diagnosticEventType"></param>
|
|
/// <param name="eventType"></param>
|
|
/// <param name="eventData"></param>
|
|
/// <param name="listenerMethod"></param>
|
|
private static void SendDiagnosticEvent(EventDiagnosticType diagnosticEventType, Type eventType, object eventData, MemberInfo listenerMethod)
|
|
{
|
|
foreach (var diagnosticEvent in DiagnosticList)
|
|
{
|
|
string listener = null;
|
|
|
|
if (listenerMethod != null && listenerMethod.DeclaringType != null)
|
|
{
|
|
listener = string.Format("{0}.{1} , {2}", listenerMethod.DeclaringType.FullName, listenerMethod.Name, listenerMethod.DeclaringType.Assembly.FullName);
|
|
}
|
|
|
|
diagnosticEvent(diagnosticEventType, eventType, eventData, listener);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public enum EventDiagnosticType
|
|
{
|
|
AddListener = 0,
|
|
AddListenerDiagnostic = 1,
|
|
PublishEvent = 2,
|
|
RemoveListenerDiagnostic = 3,
|
|
RemoveListener = 4
|
|
}
|
|
|
|
class EventMetaData<T> where T : class
|
|
{
|
|
public Predicate<T> EventFilter { get; set; }
|
|
public SubscriberCallbackDelegate<T> Callback { get; set; }
|
|
}
|
|
|
|
}
|