2016-08-02 23:54:57 +03:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Reflection;
|
2016-08-10 14:51:33 +03:00
|
|
|
using static System.String;
|
2016-08-02 23:54:57 +03:00
|
|
|
|
|
|
|
namespace Xamarin.Forms
|
|
|
|
{
|
|
|
|
internal class WeakEventManager
|
|
|
|
{
|
|
|
|
readonly Dictionary<string, List<Subscription>> _eventHandlers =
|
|
|
|
new Dictionary<string, List<Subscription>>();
|
|
|
|
|
|
|
|
public void AddEventHandler<TEventArgs>(string eventName, EventHandler<TEventArgs> handler)
|
|
|
|
where TEventArgs : EventArgs
|
|
|
|
{
|
2016-08-10 14:51:33 +03:00
|
|
|
if (IsNullOrEmpty(eventName))
|
2016-08-02 23:54:57 +03:00
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(eventName));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handler == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(handler));
|
|
|
|
}
|
|
|
|
|
|
|
|
AddEventHandler(eventName, handler.Target, handler.GetMethodInfo());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void AddEventHandler(string eventName, EventHandler handler)
|
|
|
|
{
|
2016-08-10 14:51:33 +03:00
|
|
|
if (IsNullOrEmpty(eventName))
|
2016-08-02 23:54:57 +03:00
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(eventName));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handler == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(handler));
|
|
|
|
}
|
|
|
|
|
|
|
|
AddEventHandler(eventName, handler.Target, handler.GetMethodInfo());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void HandleEvent(object sender, object args, string eventName)
|
|
|
|
{
|
|
|
|
var toRaise = new List<Tuple<object, MethodInfo>>();
|
2016-08-10 14:51:33 +03:00
|
|
|
var toRemove = new List<Subscription>();
|
2016-08-02 23:54:57 +03:00
|
|
|
|
|
|
|
List<Subscription> target;
|
|
|
|
if (_eventHandlers.TryGetValue(eventName, out target))
|
|
|
|
{
|
|
|
|
foreach (Subscription subscription in target)
|
|
|
|
{
|
2016-08-10 14:51:33 +03:00
|
|
|
bool isStatic = subscription.Subscriber == null;
|
|
|
|
if (isStatic)
|
|
|
|
{
|
|
|
|
// For a static method, we'll just pass null as the first parameter of MethodInfo.Invoke
|
|
|
|
toRaise.Add(Tuple.Create<object, MethodInfo>(null, subscription.Handler));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-08-02 23:54:57 +03:00
|
|
|
object subscriber = subscription.Subscriber.Target;
|
|
|
|
|
|
|
|
if (subscriber == null)
|
|
|
|
{
|
|
|
|
// The subscriber was collected, so there's no need to keep this subscription around
|
2016-08-10 14:51:33 +03:00
|
|
|
toRemove.Add(subscription);
|
2016-08-02 23:54:57 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
toRaise.Add(Tuple.Create(subscriber, subscription.Handler));
|
|
|
|
}
|
|
|
|
}
|
2016-08-10 14:51:33 +03:00
|
|
|
|
|
|
|
foreach (Subscription subscription in toRemove)
|
|
|
|
{
|
|
|
|
target.Remove(subscription);
|
|
|
|
}
|
2016-08-02 23:54:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
foreach (Tuple<object, MethodInfo> tuple in toRaise)
|
|
|
|
{
|
|
|
|
tuple.Item2.Invoke(tuple.Item1, new[] { sender, args });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void RemoveEventHandler<TEventArgs>(string eventName, EventHandler<TEventArgs> handler)
|
|
|
|
where TEventArgs : EventArgs
|
|
|
|
{
|
2016-08-10 14:51:33 +03:00
|
|
|
if (IsNullOrEmpty(eventName))
|
2016-08-02 23:54:57 +03:00
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(eventName));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handler == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(handler));
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveEventHandler(eventName, handler.Target, handler.GetMethodInfo());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void RemoveEventHandler(string eventName, EventHandler handler)
|
|
|
|
{
|
2016-08-10 14:51:33 +03:00
|
|
|
if (IsNullOrEmpty(eventName))
|
2016-08-02 23:54:57 +03:00
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(eventName));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handler == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(handler));
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveEventHandler(eventName, handler.Target, handler.GetMethodInfo());
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddEventHandler(string eventName, object handlerTarget, MethodInfo methodInfo)
|
|
|
|
{
|
2016-08-10 14:51:33 +03:00
|
|
|
List<Subscription> targets;
|
|
|
|
if (!_eventHandlers.TryGetValue(eventName, out targets))
|
2016-08-02 23:54:57 +03:00
|
|
|
{
|
2016-08-10 14:51:33 +03:00
|
|
|
targets = new List<Subscription>();
|
|
|
|
_eventHandlers.Add(eventName, targets);
|
2016-08-02 23:54:57 +03:00
|
|
|
}
|
|
|
|
|
2016-08-10 14:51:33 +03:00
|
|
|
if (handlerTarget == null)
|
|
|
|
{
|
|
|
|
// This event handler is a static method
|
|
|
|
targets.Add(new Subscription(null, methodInfo));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
targets.Add(new Subscription(new WeakReference(handlerTarget), methodInfo));
|
2016-08-02 23:54:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveEventHandler(string eventName, object handlerTarget, MemberInfo methodInfo)
|
|
|
|
{
|
|
|
|
List<Subscription> subscriptions;
|
|
|
|
if (!_eventHandlers.TryGetValue(eventName, out subscriptions))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int n = subscriptions.Count; n > 0; n--)
|
|
|
|
{
|
|
|
|
Subscription current = subscriptions[n - 1];
|
|
|
|
|
2018-09-26 12:21:05 +03:00
|
|
|
if (current.Subscriber?.Target != handlerTarget
|
2016-08-02 23:54:57 +03:00
|
|
|
|| current.Handler.Name != methodInfo.Name)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
subscriptions.Remove(current);
|
2018-11-29 15:58:42 +03:00
|
|
|
break;
|
2016-08-02 23:54:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Subscription
|
|
|
|
{
|
|
|
|
public Subscription(WeakReference subscriber, MethodInfo handler)
|
|
|
|
{
|
|
|
|
if (handler == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(handler));
|
|
|
|
}
|
|
|
|
|
|
|
|
Subscriber = subscriber;
|
|
|
|
Handler = handler;
|
|
|
|
}
|
|
|
|
|
|
|
|
public readonly WeakReference Subscriber;
|
|
|
|
public readonly MethodInfo Handler;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|