summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Core/WeakEventManager.cs
diff options
context:
space:
mode:
authorE.Z. Hart <hartez@users.noreply.github.com>2016-08-02 14:54:57 -0600
committerJason Smith <jason.smith@xamarin.com>2016-08-02 13:54:57 -0700
commit34048b7bb4e8bf55c712ffd92303cf260c491c0e (patch)
tree19236fb4e72b8833c87e19fd15d0958b947764fc /Xamarin.Forms.Core/WeakEventManager.cs
parent08e282350cb3f1c2345125682f14934111af2f9c (diff)
downloadxamarin-forms-34048b7bb4e8bf55c712ffd92303cf260c491c0e.tar.gz
xamarin-forms-34048b7bb4e8bf55c712ffd92303cf260c491c0e.tar.bz2
xamarin-forms-34048b7bb4e8bf55c712ffd92303cf260c491c0e.zip
Change SourceChanged event on ImageSource to weak event to allow Images (#268)
referencing application-wide StaticResource ImageSources to be GCed
Diffstat (limited to 'Xamarin.Forms.Core/WeakEventManager.cs')
-rw-r--r--Xamarin.Forms.Core/WeakEventManager.cs159
1 files changed, 159 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core/WeakEventManager.cs b/Xamarin.Forms.Core/WeakEventManager.cs
new file mode 100644
index 00000000..226f329a
--- /dev/null
+++ b/Xamarin.Forms.Core/WeakEventManager.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+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
+ {
+ if (eventName == null)
+ {
+ 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)
+ {
+ if (eventName == null)
+ {
+ 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>>();
+
+ List<Subscription> target;
+ if (_eventHandlers.TryGetValue(eventName, out target))
+ {
+ foreach (Subscription subscription in target)
+ {
+ object subscriber = subscription.Subscriber.Target;
+
+ if (subscriber == null)
+ {
+ // The subscriber was collected, so there's no need to keep this subscription around
+ target.Remove(subscription);
+ }
+ else
+ {
+ toRaise.Add(Tuple.Create(subscriber, subscription.Handler));
+ }
+ }
+ }
+
+ 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
+ {
+ if (eventName == null)
+ {
+ 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)
+ {
+ if (eventName == null)
+ {
+ 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)
+ {
+ List<Subscription> target;
+ if (!_eventHandlers.TryGetValue(eventName, out target))
+ {
+ target = new List<Subscription>();
+ _eventHandlers.Add(eventName, target);
+ }
+
+ target.Add(new Subscription(new WeakReference(handlerTarget), methodInfo));
+ }
+
+ 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];
+
+ if (current.Subscriber != handlerTarget
+ || current.Handler.Name != methodInfo.Name)
+ {
+ continue;
+ }
+
+ subscriptions.Remove(current);
+ }
+ }
+
+ struct Subscription
+ {
+ public Subscription(WeakReference subscriber, MethodInfo handler)
+ {
+ if (subscriber == null)
+ {
+ throw new ArgumentNullException(nameof(subscriber));
+ }
+
+ if (handler == null)
+ {
+ throw new ArgumentNullException(nameof(handler));
+ }
+
+ Subscriber = subscriber;
+ Handler = handler;
+ }
+
+ public readonly WeakReference Subscriber;
+ public readonly MethodInfo Handler;
+ }
+ }
+} \ No newline at end of file