Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / System / ComponentModel / PropertyChangedEventManager.cs / 1305600 / 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)
{
if (source == null)
throw new ArgumentNullException("source");
if (listener == null)
throw new ArgumentNullException("listener");
CurrentManager.PrivateAddListener(source, listener, propertyName);
}
///
/// Remove a listener to the given source's event.
///
public static void RemoveListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName)
{
/* for app-compat, allow RemoveListener(null, x) - it's a no-op (see Dev10 796788)
if (source == null)
throw new ArgumentNullException("source");
*/
if (listener == null)
throw new ArgumentNullException("listener");
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);
_proposedAllListenersList = null;
}
}
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
_proposedAllListenersList = null;
// 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
_proposedAllListenersList = null;
}
}
}
// 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)
{
if (source == null)
throw new ArgumentNullException("source");
if (listener == null)
throw new ArgumentNullException("listener");
CurrentManager.PrivateAddListener(source, listener, propertyName);
}
///
/// Remove a listener to the given source's event.
///
public static void RemoveListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName)
{
/* for app-compat, allow RemoveListener(null, x) - it's a no-op (see Dev10 796788)
if (source == null)
throw new ArgumentNullException("source");
*/
if (listener == null)
throw new ArgumentNullException("listener");
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);
_proposedAllListenersList = null;
}
}
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
_proposedAllListenersList = null;
// 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
_proposedAllListenersList = null;
}
}
}
// 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
- TagMapInfo.cs
- DataServiceQueryException.cs
- HebrewNumber.cs
- ListViewTableRow.cs
- SafeThemeHandle.cs
- ResourceAssociationTypeEnd.cs
- MenuItem.cs
- HttpFileCollection.cs
- XmlDocumentSchema.cs
- OledbConnectionStringbuilder.cs
- HandleCollector.cs
- SymmetricSecurityProtocol.cs
- UrlAuthFailedErrorFormatter.cs
- XmlName.cs
- AssertFilter.cs
- GenericsInstances.cs
- XPathCompileException.cs
- ConnectionsZone.cs
- DefaultTraceListener.cs
- SliderAutomationPeer.cs
- XmlDigitalSignatureProcessor.cs
- ListBoxItem.cs
- KnownBoxes.cs
- UnmanagedHandle.cs
- WpfPayload.cs
- ObjectDataSourceDisposingEventArgs.cs
- TextTreeInsertUndoUnit.cs
- DictionarySurrogate.cs
- XsltQilFactory.cs
- PropertyMetadata.cs
- CfgParser.cs
- SerializationInfoEnumerator.cs
- Section.cs
- XmlSchemaDatatype.cs
- BoundingRectTracker.cs
- Rotation3DKeyFrameCollection.cs
- VolatileEnlistmentState.cs
- PartialCachingAttribute.cs
- InkCanvas.cs
- CanonicalFontFamilyReference.cs
- NativeMethods.cs
- ArcSegment.cs
- PropertyDescriptor.cs
- DTCTransactionManager.cs
- MessageBuffer.cs
- WindowsFormsEditorServiceHelper.cs
- DataContractSerializerOperationGenerator.cs
- ExpressionPrefixAttribute.cs
- GridViewCommandEventArgs.cs
- AutomationPatternInfo.cs
- MailDefinitionBodyFileNameEditor.cs
- StructuredTypeInfo.cs
- Debugger.cs
- SqlAggregateChecker.cs
- ListSourceHelper.cs
- MD5.cs
- SystemIPInterfaceProperties.cs
- WorkflowRuntimeSection.cs
- SqlTypeSystemProvider.cs
- SafeNativeMethodsCLR.cs
- CachedBitmap.cs
- SqlReorderer.cs
- WebContext.cs
- RepeaterItemCollection.cs
- ContentPosition.cs
- BookmarkUndoUnit.cs
- HwndPanningFeedback.cs
- FloaterBaseParagraph.cs
- ToolboxItemAttribute.cs
- ServiceKnownTypeAttribute.cs
- PhysicalAddress.cs
- DataKeyArray.cs
- Schema.cs
- GeometryGroup.cs
- ContextCorrelationInitializer.cs
- AutomationPropertyInfo.cs
- ListView.cs
- SmiEventSink_DeferedProcessing.cs
- PointIndependentAnimationStorage.cs
- SystemIPv6InterfaceProperties.cs
- CommonProperties.cs
- WindowsRebar.cs
- HelloOperationCD1AsyncResult.cs
- CryptoConfig.cs
- ListItemCollection.cs
- XmlILStorageConverter.cs
- GetCardDetailsRequest.cs
- ILGenerator.cs
- DataListItemCollection.cs
- oledbconnectionstring.cs
- CheckBoxAutomationPeer.cs
- PrintingPermissionAttribute.cs
- KeyEventArgs.cs
- ExpressionQuoter.cs
- DtdParser.cs
- BitmapEffectInput.cs
- TraceListener.cs
- ADMembershipUser.cs
- MemberDescriptor.cs
- XmlSchemaComplexContentExtension.cs