PageRenderTime 5566ms CodeModel.GetById 37ms RepoModel.GetById 3ms app.codeStats 0ms

/MishraReader.Entities/Tools/WeakEventHandler.cs

http://mishrareader.codeplex.com
C# | 285 lines | 157 code | 48 blank | 80 comment | 29 complexity | 5b89d10c402bc1bbda9ac57bef6c9a15 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics.Contracts;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Reflection;
  7. using System.ComponentModel;
  8. namespace MishraReader
  9. {
  10. // The code in this file is from Dustin Campbell's blog at
  11. // http://diditwith.net/PermaLink,guid,aacdb8ae-7baa-4423-a953-c18c1c7940ab.aspx
  12. /// <summary>
  13. /// </summary>
  14. /// <typeparam name="E"> </typeparam>
  15. /// <param name="eventHandler"> </param>
  16. public delegate void UnregisterEventHandler<E>(EventHandler<E> eventHandler) where E : EventArgs;
  17. /// <summary>
  18. /// </summary>
  19. /// <param name="eventHandler"> </param>
  20. public delegate void UnregisterPropertyChangedEventHandler(PropertyChangedEventHandler eventHandler);
  21. /// <summary>
  22. /// </summary>
  23. /// <typeparam name="E"> </typeparam>
  24. internal interface IWeakEventHandler<E> where E : EventArgs
  25. {
  26. EventHandler<E> Handler { get; }
  27. WeakReference Target { get; }
  28. }
  29. /// <summary>
  30. /// </summary>
  31. /// <typeparam name="E"> </typeparam>
  32. internal interface IWeakPropertyChangedEventHandler
  33. {
  34. PropertyChangedEventHandler Handler { get; }
  35. WeakReference Target { get; }
  36. }
  37. /// <summary>
  38. /// Weak Event Handler, taken from: http://diditwith.net/PermaLink,guid,aacdb8ae-7baa-4423-a953-c18c1c7940ab.aspx
  39. /// </summary>
  40. /// <typeparam name="T"> </typeparam>
  41. /// <typeparam name="E"> </typeparam>
  42. internal class WeakEventHandler<T, E> : IWeakEventHandler<E>
  43. where T : class
  44. where E : EventArgs
  45. {
  46. private readonly EventHandler<E> m_Handler;
  47. private readonly OpenEventHandler m_OpenHandler;
  48. private readonly WeakReference m_TargetRef;
  49. private UnregisterEventHandler<E> m_Unregister;
  50. /// <summary>
  51. /// </summary>
  52. /// <param name="eventHandler"> </param>
  53. /// <param name="unregister"> </param>
  54. public WeakEventHandler(EventHandler<E> eventHandler, UnregisterEventHandler<E> unregister)
  55. {
  56. m_TargetRef = new WeakReference(eventHandler.Target);
  57. var mi = eventHandler.GetMethodInfo();
  58. m_OpenHandler = (OpenEventHandler)mi.CreateDelegate(typeof(OpenEventHandler), null);
  59. m_Handler = Invoke;
  60. m_Unregister = unregister;
  61. }
  62. /// <summary>
  63. /// </summary>
  64. public EventHandler<E> Handler
  65. {
  66. get { return m_Handler; }
  67. }
  68. /// <summary>
  69. /// </summary>
  70. public WeakReference Target
  71. {
  72. get { return m_TargetRef; }
  73. }
  74. /// <summary>
  75. /// </summary>
  76. /// <param name="sender"> </param>
  77. /// <param name="e"> </param>
  78. public void Invoke(object sender, E e)
  79. {
  80. var target = (T)m_TargetRef.Target;
  81. if (!ReferenceEquals(target, null))
  82. m_OpenHandler.Invoke(target, sender, e);
  83. else if (m_Unregister != null)
  84. {
  85. m_Unregister(m_Handler);
  86. m_Unregister = null;
  87. }
  88. }
  89. /// <summary>
  90. /// </summary>
  91. /// <param name="weh"> </param>
  92. /// <returns> </returns>
  93. public static implicit operator EventHandler<E>(WeakEventHandler<T, E> weh)
  94. {
  95. return weh.m_Handler;
  96. }
  97. private delegate void OpenEventHandler(T @this, object sender, E e);
  98. }
  99. /// <summary>
  100. /// Weak Event Handler, taken from: http://diditwith.net/PermaLink,guid,aacdb8ae-7baa-4423-a953-c18c1c7940ab.aspx
  101. /// </summary>
  102. /// <typeparam name="T"> </typeparam>
  103. internal class WeakPropertyChangedEventHandler<T> : IWeakPropertyChangedEventHandler
  104. where T : class
  105. {
  106. private readonly PropertyChangedEventHandler m_Handler;
  107. private readonly OpenEventHandler m_OpenHandler;
  108. private readonly WeakReference m_TargetRef;
  109. private UnregisterPropertyChangedEventHandler m_Unregister;
  110. /// <summary>
  111. /// </summary>
  112. /// <param name="eventHandler"> </param>
  113. /// <param name="unregister"> </param>
  114. public WeakPropertyChangedEventHandler(PropertyChangedEventHandler eventHandler, UnregisterPropertyChangedEventHandler unregister)
  115. {
  116. m_TargetRef = new WeakReference(eventHandler.Target);
  117. var mi = eventHandler.GetMethodInfo();
  118. m_OpenHandler = (OpenEventHandler)mi.CreateDelegate(typeof(OpenEventHandler), null);
  119. m_Handler = Invoke;
  120. m_Unregister = unregister;
  121. }
  122. /// <summary>
  123. /// </summary>
  124. public PropertyChangedEventHandler Handler
  125. {
  126. get { return m_Handler; }
  127. }
  128. /// <summary>
  129. /// </summary>
  130. public WeakReference Target
  131. {
  132. get { return m_TargetRef; }
  133. }
  134. /// <summary>
  135. /// </summary>
  136. /// <param name="sender"> </param>
  137. /// <param name="e"> </param>
  138. public void Invoke(object sender, PropertyChangedEventArgs e)
  139. {
  140. var target = (T)m_TargetRef.Target;
  141. if (!ReferenceEquals(target, null))
  142. m_OpenHandler.Invoke(target, sender, e);
  143. else if (m_Unregister != null)
  144. {
  145. m_Unregister(m_Handler);
  146. m_Unregister = null;
  147. }
  148. }
  149. /// <summary>
  150. /// </summary>
  151. /// <param name="weh"> </param>
  152. /// <returns> </returns>
  153. public static implicit operator PropertyChangedEventHandler(WeakPropertyChangedEventHandler<T> weh)
  154. {
  155. return weh.m_Handler;
  156. }
  157. private delegate void OpenEventHandler(T @this, object sender, PropertyChangedEventArgs e);
  158. }
  159. /// <summary>
  160. /// </summary>
  161. public static class EventHandlerUtils
  162. {
  163. /// <summary>
  164. /// </summary>
  165. /// <typeparam name="E"> </typeparam>
  166. /// <param name="eventHandler"> </param>
  167. /// <param name="unregister"> </param>
  168. /// <returns> </returns>
  169. public static EventHandler<E> MakeWeak<E>(this EventHandler<E> eventHandler, UnregisterEventHandler<E> unregister) where E : EventArgs
  170. {
  171. Contract.Requires<ArgumentNullException>(eventHandler != null, "eventHandler");
  172. Contract.Requires<ArgumentException>(!eventHandler.GetMethodInfo().IsStatic && eventHandler.Target != null, "Only instance methods are supported.");
  173. var method = eventHandler.GetMethodInfo();
  174. // check to see if we're already weak
  175. if (method.DeclaringType.GetTypeInfo().IsGenericType && method.DeclaringType.GetGenericTypeDefinition() == typeof(WeakEventHandler<,>))
  176. {
  177. return eventHandler;
  178. }
  179. var wehType = typeof(WeakEventHandler<,>).MakeGenericType(method.DeclaringType, typeof(E));
  180. var wehConstructor =wehType.GetTypeInfo().DeclaredConstructors.First();
  181. var weh = (IWeakEventHandler<E>)wehConstructor.Invoke(
  182. new object[] {eventHandler, unregister});
  183. return weh.Handler;
  184. }
  185. /// <summary>
  186. /// </summary>
  187. /// <typeparam name="E"> </typeparam>
  188. /// <param name="eventHandler"> </param>
  189. /// <param name="unregister"> </param>
  190. /// <returns> </returns>
  191. public static PropertyChangedEventHandler MakeWeak(this PropertyChangedEventHandler eventHandler, UnregisterPropertyChangedEventHandler unregister)
  192. {
  193. Contract.Requires<ArgumentNullException>(eventHandler != null, "eventHandler");
  194. Contract.Requires<ArgumentException>(!eventHandler.GetMethodInfo().IsStatic && eventHandler.Target != null, "Only instance methods are supported.");
  195. var method = eventHandler.GetMethodInfo();
  196. // check to see if we're already weak
  197. if (method.DeclaringType.GetTypeInfo().IsGenericType && method.DeclaringType.GetGenericTypeDefinition() == typeof(WeakPropertyChangedEventHandler<>))
  198. {
  199. return eventHandler;
  200. }
  201. var wehType = typeof(WeakPropertyChangedEventHandler<>).MakeGenericType(method.DeclaringType);
  202. var wehConstructor = wehType.GetTypeInfo().DeclaredConstructors.First();
  203. var weh = (IWeakPropertyChangedEventHandler)wehConstructor.Invoke(
  204. new object[] { eventHandler, unregister });
  205. return weh.Handler;
  206. }
  207. /// <summary>
  208. /// </summary>
  209. /// <typeparam name="E"> </typeparam>
  210. /// <param name="sourceHandler"> </param>
  211. /// <param name="value"> </param>
  212. /// <returns> </returns>
  213. public static EventHandler<E> Unregister<E>(this EventHandler<E> sourceHandler, EventHandler<E> value) where E : EventArgs
  214. {
  215. Contract.Requires<ArgumentNullException>(value != null, "value");
  216. Contract.Requires<ArgumentException>(!value.GetMethodInfo().IsStatic && value.Target != null, "Only instance methods are supported.");
  217. if (sourceHandler != null)
  218. {
  219. // look for the weak event handler in the invocation list
  220. foreach (EventHandler<E> evt in sourceHandler.GetInvocationList())
  221. {
  222. var weh = evt.Target as IWeakEventHandler<E>;
  223. if (weh != null)
  224. {
  225. var target = weh.Target.Target;
  226. if (!ReferenceEquals(target, null) && ReferenceEquals(target, value.Target))
  227. {
  228. return weh.Handler;
  229. }
  230. }
  231. }
  232. }
  233. // return the input as the default if we don't find a wrapped event handler
  234. return value;
  235. }
  236. }
  237. }