Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Base / System / ComponentModel / PropertyChangedEventManager.cs / 1 / PropertyChangedEventManager.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Manager for the PropertyChanged event in the "weak event listener" // pattern. See WeakEventTable.cs for an overview. // //--------------------------------------------------------------------------- using System; using System.Collections; // ICollection using System.Collections.Specialized; // HybridDictionary using System.ComponentModel; // INotifyPropertyChanged using System.Diagnostics; // Debug using System.Windows; // WeakEventManager namespace System.ComponentModel { ////// Manager for the INotifyPropertyChanged.PropertyChanged event. /// public class PropertyChangedEventManager : WeakEventManager { #region Constructors // // Constructors // private PropertyChangedEventManager() { } #endregion Constructors #region Public Methods // // Public Methods // ////// Add a listener to the given source's event. /// public static void AddListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) { CurrentManager.PrivateAddListener(source, listener, propertyName); } ////// Remove a listener to the given source's event. /// public static void RemoveListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) { CurrentManager.PrivateRemoveListener(source, listener, propertyName); } #endregion Public Methods #region Protected Methods // // Protected Methods // ////// Listen to the given source for the event. /// protected override void StartListening(object source) { INotifyPropertyChanged typedSource = (INotifyPropertyChanged)source; typedSource.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged); } ////// Stop listening to the given source for the event. /// protected override void StopListening(object source) { INotifyPropertyChanged typedSource = (INotifyPropertyChanged)source; typedSource.PropertyChanged -= new PropertyChangedEventHandler(OnPropertyChanged); } ////// Remove dead entries from the data for the given source. Returns true if /// some entries were actually removed. /// protected override bool Purge(object source, object data, bool purgeAll) { bool foundDirt = false; if (!purgeAll) { HybridDictionary dict = (HybridDictionary)data; // copy the keys into a separate array, so that later on // we can change the dictionary while iterating over the keys ICollection ic = dict.Keys; String[] keys = new String[ic.Count]; ic.CopyTo(keys, 0); for (int i=keys.Length-1; i>=0; --i) { if (keys[i] == AllListenersKey) continue; // ignore the special entry for now // for each key, remove dead entries in its list bool removeList = purgeAll || source == null; if (!removeList) { ListenerList list = (ListenerList)dict[keys[i]]; if (ListenerList.PrepareForWriting(ref list)) dict[keys[i]] = list; if (list.Purge()) foundDirt = true; removeList = (list.IsEmpty); } // if there are no more entries, remove the key if (removeList) { dict.Remove(keys[i]); } } if (dict.Count == 0) { // if there are no more listeners at all, remove the entry from // the main table, and prepare to stop listening purgeAll = true; if (source != null) // source may have been GC'd { this.Remove(source); } } else if (foundDirt) { // if any entries were purged, invalidate the special entry dict.Remove(AllListenersKey); } } if (purgeAll) { // stop listening. List cleanup is handled by Purge() if (source != null) // source may have been GC'd { StopListening(source); } foundDirt = true; } return foundDirt; } #endregion Protected Methods #region Private Properties // // Private Properties // // get the event manager for the current thread private static PropertyChangedEventManager CurrentManager { get { Type managerType = typeof(PropertyChangedEventManager); PropertyChangedEventManager manager = (PropertyChangedEventManager)GetCurrentManager(managerType); // at first use, create and register a new manager if (manager == null) { manager = new PropertyChangedEventManager(); SetCurrentManager(managerType, manager); } return manager; } } #endregion Private Properties #region Private Methods // // Private Methods // // PropertyChanged is a special case - we superimpose per-property granularity // on top of this event, by keeping separate lists of listeners for // each property. // Add a listener to the named property (empty means "any property") private void PrivateAddListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) { Debug.Assert(listener != null && source != null && propertyName != null, "Listener, source, and propertyName of event cannot be null"); using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict == null) { // no entry in the hashtable - add a new one dict = new HybridDictionary(true /* case insensitive */); this[source] = dict; // listen for the desired events StartListening(source); } ListenerList list = (ListenerList)dict[propertyName]; if (list == null) { // no entry in the dictionary - add a new one list = new ListenerList(); dict[propertyName] = list; } // make sure list is ready for writing if (ListenerList.PrepareForWriting(ref list)) { dict[propertyName] = list; } // add a listener to the list list.Add(listener); dict.Remove(AllListenersKey); // invalidate list of all listeners // schedule a cleanup pass ScheduleCleanup(); } } // Remove a listener to the named property (empty means "any property") private void PrivateRemoveListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) { Debug.Assert(listener != null && source != null && propertyName != null, "Listener, source, and propertyName of event cannot be null"); using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict != null) { ListenerList list = (ListenerList)dict[propertyName]; if (list != null) { // make sure list is ready for writing if (ListenerList.PrepareForWriting(ref list)) { dict[propertyName] = list; } // remove a listener from the list list.Remove(listener); // when the last listener goes away, remove the list if (list.IsEmpty) { dict.Remove(propertyName); } } if (dict.Count == 0) { StopListening(source); Remove(source); } dict.Remove(AllListenersKey); // invalidate list of all listeners } } } // event handler for PropertyChanged event private void OnPropertyChanged(object sender, PropertyChangedEventArgs args) { ListenerList list; string propertyName = args.PropertyName; // get the list of listeners using (ReadLock) { // look up the list of listeners HybridDictionary dict = (HybridDictionary)this[sender]; if (dict == null) { // this can happen when the last listener stops listening, but the // source raises the event on another thread after the dictionary // has been removed (bug 1235351) list = ListenerList.Empty; } else if (!String.IsNullOrEmpty(propertyName)) { // source has changed a particular property. Notify targets // who are listening either for this property or for all properties. ListenerList listeners = (ListenerList)dict[propertyName]; ListenerList genericListeners = (ListenerList)dict[String.Empty]; if (genericListeners == null) { if (listeners != null) { list = listeners; // only specific listeners } else { list = ListenerList.Empty; // no listeners at all } } else { if (listeners != null) { // there are both specific and generic listeners - // combine the two lists. list = new ListenerList(listeners.Count + genericListeners.Count); for (int i=0, n=listeners.Count; i// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Manager for the PropertyChanged event in the "weak event listener" // pattern. See WeakEventTable.cs for an overview. // //--------------------------------------------------------------------------- using System; using System.Collections; // ICollection using System.Collections.Specialized; // HybridDictionary using System.ComponentModel; // INotifyPropertyChanged using System.Diagnostics; // Debug using System.Windows; // WeakEventManager namespace System.ComponentModel { /// /// Manager for the INotifyPropertyChanged.PropertyChanged event. /// public class PropertyChangedEventManager : WeakEventManager { #region Constructors // // Constructors // private PropertyChangedEventManager() { } #endregion Constructors #region Public Methods // // Public Methods // ////// Add a listener to the given source's event. /// public static void AddListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) { CurrentManager.PrivateAddListener(source, listener, propertyName); } ////// Remove a listener to the given source's event. /// public static void RemoveListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) { CurrentManager.PrivateRemoveListener(source, listener, propertyName); } #endregion Public Methods #region Protected Methods // // Protected Methods // ////// Listen to the given source for the event. /// protected override void StartListening(object source) { INotifyPropertyChanged typedSource = (INotifyPropertyChanged)source; typedSource.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged); } ////// Stop listening to the given source for the event. /// protected override void StopListening(object source) { INotifyPropertyChanged typedSource = (INotifyPropertyChanged)source; typedSource.PropertyChanged -= new PropertyChangedEventHandler(OnPropertyChanged); } ////// Remove dead entries from the data for the given source. Returns true if /// some entries were actually removed. /// protected override bool Purge(object source, object data, bool purgeAll) { bool foundDirt = false; if (!purgeAll) { HybridDictionary dict = (HybridDictionary)data; // copy the keys into a separate array, so that later on // we can change the dictionary while iterating over the keys ICollection ic = dict.Keys; String[] keys = new String[ic.Count]; ic.CopyTo(keys, 0); for (int i=keys.Length-1; i>=0; --i) { if (keys[i] == AllListenersKey) continue; // ignore the special entry for now // for each key, remove dead entries in its list bool removeList = purgeAll || source == null; if (!removeList) { ListenerList list = (ListenerList)dict[keys[i]]; if (ListenerList.PrepareForWriting(ref list)) dict[keys[i]] = list; if (list.Purge()) foundDirt = true; removeList = (list.IsEmpty); } // if there are no more entries, remove the key if (removeList) { dict.Remove(keys[i]); } } if (dict.Count == 0) { // if there are no more listeners at all, remove the entry from // the main table, and prepare to stop listening purgeAll = true; if (source != null) // source may have been GC'd { this.Remove(source); } } else if (foundDirt) { // if any entries were purged, invalidate the special entry dict.Remove(AllListenersKey); } } if (purgeAll) { // stop listening. List cleanup is handled by Purge() if (source != null) // source may have been GC'd { StopListening(source); } foundDirt = true; } return foundDirt; } #endregion Protected Methods #region Private Properties // // Private Properties // // get the event manager for the current thread private static PropertyChangedEventManager CurrentManager { get { Type managerType = typeof(PropertyChangedEventManager); PropertyChangedEventManager manager = (PropertyChangedEventManager)GetCurrentManager(managerType); // at first use, create and register a new manager if (manager == null) { manager = new PropertyChangedEventManager(); SetCurrentManager(managerType, manager); } return manager; } } #endregion Private Properties #region Private Methods // // Private Methods // // PropertyChanged is a special case - we superimpose per-property granularity // on top of this event, by keeping separate lists of listeners for // each property. // Add a listener to the named property (empty means "any property") private void PrivateAddListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) { Debug.Assert(listener != null && source != null && propertyName != null, "Listener, source, and propertyName of event cannot be null"); using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict == null) { // no entry in the hashtable - add a new one dict = new HybridDictionary(true /* case insensitive */); this[source] = dict; // listen for the desired events StartListening(source); } ListenerList list = (ListenerList)dict[propertyName]; if (list == null) { // no entry in the dictionary - add a new one list = new ListenerList(); dict[propertyName] = list; } // make sure list is ready for writing if (ListenerList.PrepareForWriting(ref list)) { dict[propertyName] = list; } // add a listener to the list list.Add(listener); dict.Remove(AllListenersKey); // invalidate list of all listeners // schedule a cleanup pass ScheduleCleanup(); } } // Remove a listener to the named property (empty means "any property") private void PrivateRemoveListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) { Debug.Assert(listener != null && source != null && propertyName != null, "Listener, source, and propertyName of event cannot be null"); using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict != null) { ListenerList list = (ListenerList)dict[propertyName]; if (list != null) { // make sure list is ready for writing if (ListenerList.PrepareForWriting(ref list)) { dict[propertyName] = list; } // remove a listener from the list list.Remove(listener); // when the last listener goes away, remove the list if (list.IsEmpty) { dict.Remove(propertyName); } } if (dict.Count == 0) { StopListening(source); Remove(source); } dict.Remove(AllListenersKey); // invalidate list of all listeners } } } // event handler for PropertyChanged event private void OnPropertyChanged(object sender, PropertyChangedEventArgs args) { ListenerList list; string propertyName = args.PropertyName; // get the list of listeners using (ReadLock) { // look up the list of listeners HybridDictionary dict = (HybridDictionary)this[sender]; if (dict == null) { // this can happen when the last listener stops listening, but the // source raises the event on another thread after the dictionary // has been removed (bug 1235351) list = ListenerList.Empty; } else if (!String.IsNullOrEmpty(propertyName)) { // source has changed a particular property. Notify targets // who are listening either for this property or for all properties. ListenerList listeners = (ListenerList)dict[propertyName]; ListenerList genericListeners = (ListenerList)dict[String.Empty]; if (genericListeners == null) { if (listeners != null) { list = listeners; // only specific listeners } else { list = ListenerList.Empty; // no listeners at all } } else { if (listeners != null) { // there are both specific and generic listeners - // combine the two lists. list = new ListenerList(listeners.Count + genericListeners.Count); for (int i=0, n=listeners.Count; i
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EntityDataSourceQueryBuilder.cs
- DynamicILGenerator.cs
- SQLBytes.cs
- BaseDataBoundControl.cs
- TrackingMemoryStream.cs
- ColorConvertedBitmapExtension.cs
- Validator.cs
- OdbcError.cs
- SqlCachedBuffer.cs
- SqlDataSourceCommandEventArgs.cs
- DiscoveryClientRequestChannel.cs
- PrintDialog.cs
- WebPartManager.cs
- ReadWriteObjectLock.cs
- XmlSerializationReader.cs
- odbcmetadatacollectionnames.cs
- DataGridSortCommandEventArgs.cs
- DynamicValidatorEventArgs.cs
- SerializationBinder.cs
- StorageSetMapping.cs
- ContainerParagraph.cs
- DockPattern.cs
- ToolStripSeparatorRenderEventArgs.cs
- ProxyHwnd.cs
- QueueProcessor.cs
- SystemKeyConverter.cs
- KerberosReceiverSecurityToken.cs
- TextElementCollection.cs
- TableItemPatternIdentifiers.cs
- ProfileBuildProvider.cs
- HtmlPageAdapter.cs
- XmlReflectionMember.cs
- CellQuery.cs
- ResourcePool.cs
- _NetworkingPerfCounters.cs
- RequestQueryProcessor.cs
- Quad.cs
- Configuration.cs
- BitmapEffectState.cs
- LinkTarget.cs
- IgnoreFileBuildProvider.cs
- VerificationAttribute.cs
- WhitespaceSignificantCollectionAttribute.cs
- PartManifestEntry.cs
- RegularExpressionValidator.cs
- FocusManager.cs
- DataGridViewIntLinkedList.cs
- SqlBooleanMismatchVisitor.cs
- ExceptionCollection.cs
- _NestedSingleAsyncResult.cs
- BindingWorker.cs
- EdmRelationshipRoleAttribute.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- MethodExpression.cs
- SchemaMapping.cs
- versioninfo.cs
- CngKeyCreationParameters.cs
- configsystem.cs
- EntityTypeBase.cs
- MsmqException.cs
- SessionPageStateSection.cs
- ConfigXmlCDataSection.cs
- BufferedGraphics.cs
- DefaultObjectMappingItemCollection.cs
- GenericTextProperties.cs
- ConsoleTraceListener.cs
- BaseDataBoundControl.cs
- InheritanceAttribute.cs
- BitmapInitialize.cs
- SolidBrush.cs
- FormatException.cs
- SByte.cs
- TheQuery.cs
- ClientScriptManagerWrapper.cs
- EditBehavior.cs
- ObjectMaterializedEventArgs.cs
- Filter.cs
- TypeConstant.cs
- SchemaElementLookUpTableEnumerator.cs
- XmlRootAttribute.cs
- WaitHandleCannotBeOpenedException.cs
- TextReader.cs
- DelegatingTypeDescriptionProvider.cs
- ProfileEventArgs.cs
- DbSource.cs
- XmlDictionaryWriter.cs
- IdentityManager.cs
- ReferenceConverter.cs
- xmlglyphRunInfo.cs
- LinqDataSourceHelper.cs
- WindowsEditBox.cs
- GraphicsContext.cs
- LocalBuilder.cs
- EdmItemError.cs
- InputEventArgs.cs
- BitmapEffectInputConnector.cs
- GenericPrincipal.cs
- UrlUtility.cs
- PolyQuadraticBezierSegmentFigureLogic.cs
- ClientScriptManagerWrapper.cs