View Code
1 //=================================================================================== 2 // Microsoft patterns & practices 3 // Composite Application Guidance for Windows Presentation Foundation and Silverlight 4 //=================================================================================== 5 // Copyright (c) Microsoft Corporation. All rights reserved. 6 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 7 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT 8 // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 9 // FITNESS FOR A PARTICULAR PURPOSE. 10 //=================================================================================== 11 // The example companies, organizations, products, domain names, 12 // e-mail addresses, logos, people, places, and events depicted 13 // herein are fictitious. No association with any real company, 14 // organization, product, domain name, email address, logo, person, 15 // places, or events is intended or should be inferred. 16 //=================================================================================== 17 using System; 18 using System.Collections.Generic; 19 using System.Windows.Threading; 20 using System.Windows; 21 22 namespace Microsoft.Practices.Prism.Commands 23 { 24 /// <summary> 25 /// Handles management and dispatching of EventHandlers in a weak way. 26 /// </summary> 27 internal static class WeakEventHandlerManager 28 { 29 ///<summary> 30 /// Invokes the handlers 31 ///</summary> 32 ///<param name="sender"></param> 33 ///<param name="handlers"></param> 34 public static void CallWeakReferenceHandlers(object sender, List<WeakReference> handlers) 35 { 36 if (handlers != null) 37 { 38 // Take a snapshot of the handlers before we call out to them since the handlers 39 // could cause the array to me modified while we are reading it. 40 EventHandler[] callees = new EventHandler[handlers.Count]; 41 int count = 0; 42 43 //Clean up handlers 44 count = CleanupOldHandlers(handlers, callees, count); 45 46 // Call the handlers that we snapshotted 47 for (int i = 0; i < count; i++) 48 { 49 CallHandler(sender, callees[i]); 50 } 51 } 52 } 53 54 private static void CallHandler(object sender, EventHandler eventHandler) 55 { 56 DispatcherProxy dispatcher = DispatcherProxy.CreateDispatcher(); 57 58 if (eventHandler != null) 59 { 60 if (dispatcher != null && !dispatcher.CheckAccess()) 61 { 62 dispatcher.BeginInvoke((Action<object, EventHandler>)CallHandler, sender, eventHandler); 63 } 64 else 65 { 66 eventHandler(sender, EventArgs.Empty); 67 } 68 } 69 } 70 71 /// <summary> 72 /// Hides the dispatcher mis-match between Silverlight and .Net, largely so code reads a bit easier 73 /// </summary> 74 private class DispatcherProxy 75 { 76 Dispatcher innerDispatcher; 77 78 private DispatcherProxy(Dispatcher dispatcher) 79 { 80 innerDispatcher = dispatcher; 81 } 82 83 public static DispatcherProxy CreateDispatcher() 84 { 85 DispatcherProxy proxy = null; 86 #if SILVERLIGHT 87 if (Deployment.Current == null) 88 return null; 89 90 proxy = new DispatcherProxy(Deployment.Current.Dispatcher); 91 #else 92 if (Application.Current == null) 93 return null; 94 95 proxy = new DispatcherProxy(Application.Current.Dispatcher); 96 #endif 97 return proxy; 98 99 } 100 101 public bool CheckAccess() 102 { 103 return innerDispatcher.CheckAccess(); 104 } 105 106 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Portability", "CA1903:UseOnlyApiFromTargetedFramework", MessageId = "System.Windows.Threading.Dispatcher.#BeginInvoke(System.Delegate,System.Windows.Threading.DispatcherPriority,System.Object[])")] 107 public DispatcherOperation BeginInvoke(Delegate method, params Object[] args) 108 { 109 #if SILVERLIGHT 110 return innerDispatcher.BeginInvoke(method, args); 111 #else 112 return innerDispatcher.BeginInvoke(method, DispatcherPriority.Normal, args); 113 #endif 114 } 115 } 116 117 private static int CleanupOldHandlers(List<WeakReference> handlers, EventHandler[] callees, int count) 118 { 119 for (int i = handlers.Count - 1; i >= 0; i--) 120 { 121 WeakReference reference = handlers[i]; 122 EventHandler handler = reference.Target as EventHandler; 123 if (handler == null) 124 { 125 // Clean up old handlers that have been collected 126 handlers.RemoveAt(i); 127 } 128 else 129 { 130 callees[count] = handler; 131 count++; 132 } 133 } 134 return count; 135 } 136 137 ///<summary> 138 /// Adds a handler to the supplied list in a weak way. 139 ///</summary> 140 ///<param name="handlers">Existing handler list. It will be created if null.</param> 141 ///<param name="handler">Handler to add.</param> 142 ///<param name="defaultListSize">Default list size.</param> 143 public static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler, int defaultListSize) 144 { 145 if (handlers == null) 146 { 147 handlers = (defaultListSize > 0 ? new List<WeakReference>(defaultListSize) : new List<WeakReference>()); 148 } 149 150 handlers.Add(new WeakReference(handler)); 151 } 152 153 ///<summary> 154 /// Removes an event handler from the reference list. 155 ///</summary> 156 ///<param name="handlers">Handler list to remove reference from.</param> 157 ///<param name="handler">Handler to remove.</param> 158 public static void RemoveWeakReferenceHandler(List<WeakReference> handlers, EventHandler handler) 159 { 160 if (handlers != null) 161 { 162 for (int i = handlers.Count - 1; i >= 0; i--) 163 { 164 WeakReference reference = handlers[i]; 165 EventHandler existingHandler = reference.Target as EventHandler; 166 if ((existingHandler == null) || (existingHandler == handler)) 167 { 168 // Clean up old handlers that have been collected 169 // in addition to the handler that is to be removed. 170 handlers.RemoveAt(i); 171 } 172 } 173 } 174 } 175 } 176 }