Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / MS / Internal / Data / ValueChangedEventManager.cs / 1 / ValueChangedEventManager.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Manager for the ValueChanged event in the "weak event listener" // pattern. See WeakEventTable.cs for an overview. // //--------------------------------------------------------------------------- /***************************************************************************\ The "value changed" pattern doesn't use events. To listen for changes in a property, a client first obtains the PropertyDescriptor for that property, then calls the AddValueChanged method to register a callback. The arguments to the callback don't say which property has changed(!). The standard manager implementation doesn't work for this. Hence this manager overrides and/or ignores the base class methods. This manager keeps a table of records, indexed by PropertyDescriptor. Each record holds the following information: PropertyDescriptor Callback method ListenerList In short, there's a separate callback method for each property. That method knows which property has changed, and can ask the manager to deliver the "event" to the listeners that are interested in that property. \****************************************************************************/ using System; using System.Collections; // ICollection using System.Collections.Specialized; // HybridDictionary using System.ComponentModel; // PropertyDescriptor using System.Diagnostics; // Debug using System.Windows; // WeakEventManager namespace MS.Internal.Data { ////// Manager for the object.ValueChanged event. /// internal class ValueChangedEventManager : WeakEventManager { #region Constructors // // Constructors // private ValueChangedEventManager() { } #endregion Constructors #region Public Methods // // Public Methods // ////// Add a listener to the given source's event. /// public static void AddListener(object source, IWeakEventListener listener, PropertyDescriptor pd) { CurrentManager.PrivateAddListener(source, listener, pd); } ////// Remove a listener to the given source's event. /// public static void RemoveListener(object source, IWeakEventListener listener, PropertyDescriptor pd) { CurrentManager.PrivateRemoveListener(source, listener, pd); } #endregion Public Methods #region Protected Methods // // Protected Methods // // The next two methods need to be defined, but they're never called. ////// Listen to the given source for the event. /// protected override void StartListening(object source) { } ////// Stop listening to the given source for the event. /// protected override void StopListening(object source) { } ////// 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; 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; PropertyDescriptor[] keys = new PropertyDescriptor[ic.Count]; ic.CopyTo(keys, 0); for (int i=keys.Length-1; i>=0; --i) { // for each key, remove dead entries in its list bool removeList = purgeAll || source == null; ValueChangedRecord record = (ValueChangedRecord)dict[keys[i]]; if (!removeList) { if (record.Purge()) foundDirt = true; removeList = record.IsEmpty; } // if there are no more entries, remove the key if (removeList) { record.StopListening(); if (!purgeAll) { dict.Remove(keys[i]); } } } // if there are no more listeners at all, remove the entry from // the main table if (dict.Count == 0) { foundDirt = true; if (source != null) // source may have been GC'd { this.Remove(source); } } return foundDirt; } #endregion Protected Methods #region Private Properties // // Private Properties // // get the event manager for the current thread private static ValueChangedEventManager CurrentManager { get { Type managerType = typeof(ValueChangedEventManager); ValueChangedEventManager manager = (ValueChangedEventManager)GetCurrentManager(managerType); // at first use, create and register a new manager if (manager == null) { manager = new ValueChangedEventManager(); SetCurrentManager(managerType, manager); } return manager; } } #endregion Private Properties #region Private Methods // // Private Methods // // Add a listener to the given property private void PrivateAddListener(object source, IWeakEventListener listener, PropertyDescriptor pd) { Debug.Assert(listener != null && source != null && pd != null, "Listener, source, and pd 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(); this[source] = dict; } ValueChangedRecord record = (ValueChangedRecord)dict[pd]; if (record == null) { // no entry in the dictionary - add a new one record = new ValueChangedRecord(this, source, pd); dict[pd] = record; } // add a listener to the list record.Add(listener); // schedule a cleanup pass ScheduleCleanup(); } } // Remove a listener to the named property (empty means "any property") private void PrivateRemoveListener(object source, IWeakEventListener listener, PropertyDescriptor pd) { Debug.Assert(listener != null && source != null && pd != null, "Listener, source, and pd of event cannot be null"); using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict != null) { ValueChangedRecord record = (ValueChangedRecord)dict[pd]; if (record != null) { // remove a listener from the list record.Remove(listener); // when the last listener goes away, remove the list if (record.IsEmpty) { dict.Remove(pd); } } if (dict.Count == 0) { Remove(source); } } } } #endregion Private Methods #region ValueChangedRecord private class ValueChangedRecord { public ValueChangedRecord(ValueChangedEventManager manager, object source, PropertyDescriptor pd) { _manager = manager; _source.Target = source; _pd = pd; _eventArgs = new ValueChangedEventArgs(pd); pd.AddValueChanged(source, new EventHandler(OnValueChanged)); } public bool IsEmpty { get { return _listeners.IsEmpty; } } // add a listener public void Add(IWeakEventListener listener) { // make sure list is ready for writing ListenerList.PrepareForWriting(ref _listeners); _listeners.Add(listener); } // remove a listener public void Remove(IWeakEventListener listener) { // make sure list is ready for writing ListenerList.PrepareForWriting(ref _listeners); _listeners.Remove(listener); // when the last listener goes away, remove the callback if (_listeners.IsEmpty) { StopListening(); } } // purge dead entries public bool Purge() { ListenerList.PrepareForWriting(ref _listeners); return _listeners.Purge(); } // remove the callback from the PropertyDescriptor public void StopListening() { object source = _source.Target; if (source != null) { _source.Target = null; _pd.RemoveValueChanged(source, new EventHandler(OnValueChanged)); } } // forward the ValueChanged event to the listeners private void OnValueChanged(object sender, EventArgs e) { // mark the list of listeners "in use" using (_manager.ReadLock) { _listeners.BeginUse(); } // deliver the event, being sure to undo the effect of BeginUse(). try { _manager.DeliverEventToList(sender, _eventArgs, _listeners); } finally { _listeners.EndUse(); } } PropertyDescriptor _pd; ValueChangedEventManager _manager; WeakReference _source = new WeakReference(null); ListenerList _listeners = new ListenerList(); ValueChangedEventArgs _eventArgs; } #endregion ValueChangedRecord } #region ValueChangedEventArgs internal class ValueChangedEventArgs : EventArgs { internal ValueChangedEventArgs(PropertyDescriptor pd) { _pd = pd; } internal PropertyDescriptor PropertyDescriptor { get { return _pd; } } private PropertyDescriptor _pd; } #endregion ValueChangedEventArgs } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Manager for the ValueChanged event in the "weak event listener" // pattern. See WeakEventTable.cs for an overview. // //--------------------------------------------------------------------------- /***************************************************************************\ The "value changed" pattern doesn't use events. To listen for changes in a property, a client first obtains the PropertyDescriptor for that property, then calls the AddValueChanged method to register a callback. The arguments to the callback don't say which property has changed(!). The standard manager implementation doesn't work for this. Hence this manager overrides and/or ignores the base class methods. This manager keeps a table of records, indexed by PropertyDescriptor. Each record holds the following information: PropertyDescriptor Callback method ListenerList In short, there's a separate callback method for each property. That method knows which property has changed, and can ask the manager to deliver the "event" to the listeners that are interested in that property. \****************************************************************************/ using System; using System.Collections; // ICollection using System.Collections.Specialized; // HybridDictionary using System.ComponentModel; // PropertyDescriptor using System.Diagnostics; // Debug using System.Windows; // WeakEventManager namespace MS.Internal.Data { ////// Manager for the object.ValueChanged event. /// internal class ValueChangedEventManager : WeakEventManager { #region Constructors // // Constructors // private ValueChangedEventManager() { } #endregion Constructors #region Public Methods // // Public Methods // ////// Add a listener to the given source's event. /// public static void AddListener(object source, IWeakEventListener listener, PropertyDescriptor pd) { CurrentManager.PrivateAddListener(source, listener, pd); } ////// Remove a listener to the given source's event. /// public static void RemoveListener(object source, IWeakEventListener listener, PropertyDescriptor pd) { CurrentManager.PrivateRemoveListener(source, listener, pd); } #endregion Public Methods #region Protected Methods // // Protected Methods // // The next two methods need to be defined, but they're never called. ////// Listen to the given source for the event. /// protected override void StartListening(object source) { } ////// Stop listening to the given source for the event. /// protected override void StopListening(object source) { } ////// 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; 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; PropertyDescriptor[] keys = new PropertyDescriptor[ic.Count]; ic.CopyTo(keys, 0); for (int i=keys.Length-1; i>=0; --i) { // for each key, remove dead entries in its list bool removeList = purgeAll || source == null; ValueChangedRecord record = (ValueChangedRecord)dict[keys[i]]; if (!removeList) { if (record.Purge()) foundDirt = true; removeList = record.IsEmpty; } // if there are no more entries, remove the key if (removeList) { record.StopListening(); if (!purgeAll) { dict.Remove(keys[i]); } } } // if there are no more listeners at all, remove the entry from // the main table if (dict.Count == 0) { foundDirt = true; if (source != null) // source may have been GC'd { this.Remove(source); } } return foundDirt; } #endregion Protected Methods #region Private Properties // // Private Properties // // get the event manager for the current thread private static ValueChangedEventManager CurrentManager { get { Type managerType = typeof(ValueChangedEventManager); ValueChangedEventManager manager = (ValueChangedEventManager)GetCurrentManager(managerType); // at first use, create and register a new manager if (manager == null) { manager = new ValueChangedEventManager(); SetCurrentManager(managerType, manager); } return manager; } } #endregion Private Properties #region Private Methods // // Private Methods // // Add a listener to the given property private void PrivateAddListener(object source, IWeakEventListener listener, PropertyDescriptor pd) { Debug.Assert(listener != null && source != null && pd != null, "Listener, source, and pd 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(); this[source] = dict; } ValueChangedRecord record = (ValueChangedRecord)dict[pd]; if (record == null) { // no entry in the dictionary - add a new one record = new ValueChangedRecord(this, source, pd); dict[pd] = record; } // add a listener to the list record.Add(listener); // schedule a cleanup pass ScheduleCleanup(); } } // Remove a listener to the named property (empty means "any property") private void PrivateRemoveListener(object source, IWeakEventListener listener, PropertyDescriptor pd) { Debug.Assert(listener != null && source != null && pd != null, "Listener, source, and pd of event cannot be null"); using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict != null) { ValueChangedRecord record = (ValueChangedRecord)dict[pd]; if (record != null) { // remove a listener from the list record.Remove(listener); // when the last listener goes away, remove the list if (record.IsEmpty) { dict.Remove(pd); } } if (dict.Count == 0) { Remove(source); } } } } #endregion Private Methods #region ValueChangedRecord private class ValueChangedRecord { public ValueChangedRecord(ValueChangedEventManager manager, object source, PropertyDescriptor pd) { _manager = manager; _source.Target = source; _pd = pd; _eventArgs = new ValueChangedEventArgs(pd); pd.AddValueChanged(source, new EventHandler(OnValueChanged)); } public bool IsEmpty { get { return _listeners.IsEmpty; } } // add a listener public void Add(IWeakEventListener listener) { // make sure list is ready for writing ListenerList.PrepareForWriting(ref _listeners); _listeners.Add(listener); } // remove a listener public void Remove(IWeakEventListener listener) { // make sure list is ready for writing ListenerList.PrepareForWriting(ref _listeners); _listeners.Remove(listener); // when the last listener goes away, remove the callback if (_listeners.IsEmpty) { StopListening(); } } // purge dead entries public bool Purge() { ListenerList.PrepareForWriting(ref _listeners); return _listeners.Purge(); } // remove the callback from the PropertyDescriptor public void StopListening() { object source = _source.Target; if (source != null) { _source.Target = null; _pd.RemoveValueChanged(source, new EventHandler(OnValueChanged)); } } // forward the ValueChanged event to the listeners private void OnValueChanged(object sender, EventArgs e) { // mark the list of listeners "in use" using (_manager.ReadLock) { _listeners.BeginUse(); } // deliver the event, being sure to undo the effect of BeginUse(). try { _manager.DeliverEventToList(sender, _eventArgs, _listeners); } finally { _listeners.EndUse(); } } PropertyDescriptor _pd; ValueChangedEventManager _manager; WeakReference _source = new WeakReference(null); ListenerList _listeners = new ListenerList(); ValueChangedEventArgs _eventArgs; } #endregion ValueChangedRecord } #region ValueChangedEventArgs internal class ValueChangedEventArgs : EventArgs { internal ValueChangedEventArgs(PropertyDescriptor pd) { _pd = pd; } internal PropertyDescriptor PropertyDescriptor { get { return _pd; } } private PropertyDescriptor _pd; } #endregion ValueChangedEventArgs } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ImagingCache.cs
- AuthStoreRoleProvider.cs
- XmlCharacterData.cs
- MemberDescriptor.cs
- Propagator.JoinPropagator.JoinPredicateVisitor.cs
- StackOverflowException.cs
- RowVisual.cs
- Matrix.cs
- ToolstripProfessionalRenderer.cs
- PropertySet.cs
- OrderedDictionary.cs
- StaticSiteMapProvider.cs
- XamlReader.cs
- ArgIterator.cs
- XmlSchemaComplexContentExtension.cs
- ListBoxItemAutomationPeer.cs
- HttpModulesSection.cs
- CryptographicAttribute.cs
- CollectionBuilder.cs
- TargetInvocationException.cs
- AspCompat.cs
- DataGridViewTopRowAccessibleObject.cs
- WebExceptionStatus.cs
- HttpServerVarsCollection.cs
- PersonalizationState.cs
- WindowsIPAddress.cs
- FixedDocumentSequencePaginator.cs
- DataControlCommands.cs
- SrgsText.cs
- InternalMappingException.cs
- Size3DValueSerializer.cs
- BamlBinaryReader.cs
- ObjectStorage.cs
- QilSortKey.cs
- XmlSiteMapProvider.cs
- RuntimeArgumentHandle.cs
- ExchangeUtilities.cs
- LessThan.cs
- Crypto.cs
- BitmapPalettes.cs
- RequestCacheManager.cs
- EUCJPEncoding.cs
- BitmapMetadataBlob.cs
- ProgressBarRenderer.cs
- RegisteredArrayDeclaration.cs
- SharedConnectionListener.cs
- WebPartRestoreVerb.cs
- ReflectionUtil.cs
- XmlSerializerSection.cs
- CounterSampleCalculator.cs
- QilChoice.cs
- EntityWrapper.cs
- OlePropertyStructs.cs
- WindowsIdentity.cs
- TypeBuilderInstantiation.cs
- TextDpi.cs
- AuthenticationService.cs
- Visual3D.cs
- EventLogInformation.cs
- BufferedReadStream.cs
- SecurityProtocolFactory.cs
- FlowDocumentScrollViewer.cs
- ErrorTableItemStyle.cs
- ReachSerializableProperties.cs
- XmlSchemaAnnotated.cs
- ProfileGroupSettingsCollection.cs
- BitmapEffectState.cs
- RequiredAttributeAttribute.cs
- SafeRegistryHandle.cs
- Queue.cs
- QueryResult.cs
- ExpressionTable.cs
- DateTimeParse.cs
- PostBackTrigger.cs
- StylusPointCollection.cs
- AudioDeviceOut.cs
- SelectionEditor.cs
- FormsAuthenticationUserCollection.cs
- ChannelManager.cs
- XsltFunctions.cs
- PageCodeDomTreeGenerator.cs
- x509utils.cs
- ChannelPool.cs
- PathFigureCollection.cs
- XmlAtomicValue.cs
- InputMethodStateChangeEventArgs.cs
- StructuredTypeInfo.cs
- XmlDocumentSurrogate.cs
- ResourceDictionary.cs
- ObsoleteAttribute.cs
- SessionStateSection.cs
- InputProviderSite.cs
- QuestionEventArgs.cs
- MouseWheelEventArgs.cs
- HttpWriter.cs
- UntrustedRecipientException.cs
- SqlClientMetaDataCollectionNames.cs
- BuildProvider.cs
- RenderDataDrawingContext.cs
- RuntimeConfig.cs