thought it will be useful,
you can use it like this:
you can use it like this:
lsnr = new GenericWeakEventListener<MyControl>(Handler); GenericWeakEventManager<MyControl>.AddListener(MyControl.ClickEvent, _mc, lsnr);privatevoid Handler(object sender, RoutedEventArgs e) { Debug.WriteLine("Clicked!"); }
which is like doing
_mc.Click += Handler
Just that it prevents the memory leak by using microsoft weak event pattern
when you make your controls
without you needing to implement one of your own
for other routed events in to control create another listener like this:
lsnr2 = new GenericWeakEventListener<MyControl>(Handler2);
GenericWeakEventManager<MyControl>.AddListener(MyControl.Click2Event, _mc, lsnr2);
which is like:
_mc.Click2 += Handler2;
|
|
|
here is the code:
using System;using System.Diagnostics;using System.Windows;namespace MyApp.WeakEvent {publicclass GenericWeakEventListener<T> : IWeakEventListener, IDisposablewhere T : FrameworkElement {public GenericWeakEventListener(RoutedEventHandler handler) { _handler = handler; }private RoutedEventHandler _handler;publicbool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) {var re = (RoutedEventArgs)e;if (managerType == typeof(GenericWeakEventManager<T>) && (re.RoutedEvent == _e)) { OnEvent(sender, re);returntrue; }returnfalse; }privatebool _isInit = false;publicvoid Init(RoutedEvent e, T t) {if (_isInit)thrownew InvalidOperationException("create another instance of the listener"); _e = e; _t = new WeakReference(t); _isInit = true; }private RoutedEvent _e;private WeakReference _t;privatevoid OnEvent(object sender, RoutedEventArgs e) {if (_handler != null) { _handler(sender, e); } }privatebool _disposed = false; ~GenericWeakEventListener() { Dispose(false);#if DEBUG Debug.WriteLine("GC Deleted: GenericWeakEventListener<"+ typeof(T).Name + ">");#endif }publicvoid Dispose() { Dispose(true); GC.SuppressFinalize(this); }privatevoid Dispose(bool disposing) {if (!_disposed && disposing && _t.IsAlive) { GenericWeakEventManager<T>.RemoveListener(_e, (T)_t.Target, (IWeakEventListener)this);#if DEBUG Debug.WriteLine("Disposing: GenericWeakEventListener<"+ typeof(T).Name + ">");#endif } _handler = null; _e = null; _t = null; _disposed = true; } }publicclass GenericWeakEventManager<T> : WeakEventManagerwhere T : FrameworkElement //can also be Control {private GenericWeakEventManager(RoutedEvent e) {if (e.OwnerType != typeof(T))thrownew InvalidOperationException("event doesn't exists in T"); _event = e; } privatereadonly RoutedEvent _event;publicstaticvoid AddListener(RoutedEvent e, DependencyObject source, GenericWeakEventListener<T> listener) { listener.Init(e, (T)source); AddListener(e, source, (IWeakEventListener)listener); }publicstaticvoid RemoveListener(RoutedEvent e, DependencyObject source, GenericWeakEventListener<T> listener) { listener.Dispose(); }publicstaticvoid AddListener(RoutedEvent e, DependencyObject source, IWeakEventListener listener) {lock (_lock) { GetCurrentManager(e); AddListener(source, listener); } }publicstaticvoid RemoveListener(RoutedEvent e, DependencyObject source, IWeakEventListener listener) {lock (_lock) { GetCurrentManager(e); RemoveListener(source, listener); } }///<summary>/// Add a listener to the given source's event.///</summary>privatestaticvoid AddListener(DependencyObject source, IWeakEventListener listener) {if (source == null)thrownew ArgumentNullException("source");if (listener == null)thrownew ArgumentNullException("listener"); CurrentManager.ProtectedAddListener(source, listener); } ///<summary>/// Remove a listener to the given source's event. /// no need to call, only implement the opposite of add, and it will be called automatically when needed///</summary>privatestaticvoid RemoveListener(DependencyObject source, IWeakEventListener listener) {if (source == null)thrownew ArgumentNullException("source");if (listener == null)thrownew ArgumentNullException("listener"); CurrentManager.ProtectedRemoveListener(source, listener); } ///<summary>/// Listen to the given source for the event.///</summary>protectedoverridevoid StartListening(object source) {var fe = source as T;if (fe != null) fe.AddHandler(_event, (RoutedEventHandler)DeliverEvent); }///<summary>/// Stop listening to the given source for the event.///</summary>protectedoverridevoid StopListening(object source) {var fe = source as T;if (fe != null) fe.RemoveHandler(_event, (RoutedEventHandler)DeliverEvent); }// get the event manager for the current thread & eventprivatestatic GenericWeakEventManager<T> CurrentManager {get { SetCurrentManager(typeof(GenericWeakEventManager<T>), _mgr);//ensure it's therereturn _mgr; }set { _mgr = value; SetCurrentManager(typeof(GenericWeakEventManager<T>), _mgr); } }privatestatic GenericWeakEventManager<T> _mgr = null;privatestaticreadonlyobject _lock = newobject();privatestatic WeakEventManager GetCurrentManager(RoutedEvent e) { Dictionary<RoutedEvent, GenericWeakEventManager<T>> d; GenericWeakEventManager<T> m;if (_dic.TryGetValue(typeof(T), out d)) {if (!d.TryGetValue(e, out m)) { m = new GenericWeakEventManager<T>(e); d.Add(e, m); } }else { d = new Dictionary<RoutedEvent, GenericWeakEventManager<T>>(); m = new GenericWeakEventManager<T>(e); d.Add(e, m); _dic.Add(typeof(T), d); } CurrentManager = m; return m; }privatestaticreadonly Dictionary<Type, Dictionary<RoutedEvent, GenericWeakEventManager<T>>> _dic = new Dictionary<Type, Dictionary<RoutedEvent, GenericWeakEventManager<T>>>(); } }