Created
January 10, 2017 01:52
-
-
Save aloisdeniel/9689a7ffb403bd85e206487fbb8bd970 to your computer and use it in GitHub Desktop.
Weak event handlers to avoid keeping strong reference to subscriber of an event.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Utils | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.Reflection; | |
/// <summary> | |
/// Weak event handlers to avoid keeping strong reference to subscriber of an event. | |
/// </summary> | |
public static class WeakEventHandlers | |
{ | |
public static List<IWeakEventHandler> subscriptions = new List<IWeakEventHandler>(); | |
public static DateTime LastPurge { get; private set; } = DateTime.Now; | |
public static TimeSpan PurgeIntervalle = TimeSpan.FromSeconds(10); | |
/// <summary> | |
/// Adds the weak event handler. | |
/// </summary> | |
/// <param name="source">Source.</param> | |
/// <param name="eventName">Event name.</param> | |
/// <param name="handler">Handler.</param> | |
/// <typeparam name="TEventArgs">The 1st type parameter.</typeparam> | |
public static void AddWeakHandler<TEventArgs>(this object source, string eventName, EventHandler<TEventArgs> handler) where TEventArgs : EventArgs | |
{ | |
var whandler = new WeakEventHandler<TEventArgs>(source, eventName, handler); | |
subscriptions.Add(whandler); | |
if (DateTime.Now - LastPurge >= PurgeIntervalle) | |
{ | |
Purge(); | |
} | |
} | |
/// <summary> | |
/// Purge all event subscriptions which target has been garbage collected. | |
/// </summary> | |
public static void Purge() | |
{ | |
for (int i = 0; i < subscriptions.Count; ) | |
{ | |
var subscription = subscriptions[i]; | |
if (subscription.CheckUnsubscribe()) | |
{ | |
subscriptions.Remove(subscription); | |
} | |
else | |
{ | |
i++; | |
} | |
} | |
LastPurge = DateTime.Now; | |
} | |
} | |
public interface IWeakEventHandler | |
{ | |
bool CheckUnsubscribe(); | |
} | |
/// <summary> | |
/// A light event handler, only this object will be kept in memory (and will keep a reference to source). | |
/// This could be considered as acceptable. | |
/// </summary> | |
public class WeakEventHandler<TEventArgs> : IWeakEventHandler where TEventArgs : EventArgs | |
{ | |
public WeakEventHandler(object source, string eventName, EventHandler<TEventArgs> target) | |
{ | |
this.eventInfo = source.GetType().GetEvent(eventName); | |
this.targetReference = new WeakReference(target.Target); | |
this.targetMethod = target.Method; | |
var methodInfo = this.GetType().GetMethod(nameof(OnEvent), BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); | |
eventHandler = Delegate.CreateDelegate(this.eventInfo.EventHandlerType, this, methodInfo); | |
this.eventInfo.AddEventHandler(source, eventHandler); | |
} | |
#region Fields | |
private Delegate eventHandler; | |
private readonly EventInfo eventInfo; | |
private readonly WeakReference targetReference; | |
private readonly MethodInfo targetMethod; | |
#endregion | |
private void OnEvent(object sender, TEventArgs args) | |
{ | |
if (this.targetReference.IsAlive) | |
{ | |
this.targetMethod.Invoke(this.targetReference.Target, new object[] { sender, args }); | |
} | |
} | |
public bool CheckUnsubscribe() | |
{ | |
if (!targetReference.IsAlive) | |
{ | |
this.@event.RemoveEventHandler(this,eventHandler); | |
return true; | |
} | |
return false; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
viewmodel.AddWeakHandler<PropertyChangedEventArgs>(nameof(INotifyPropertyChanged.PropertyChanged), this.OnViewModelPropertyChanged); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment