Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / 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.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ObjectRef.cs
- ClonableStack.cs
- StreamInfo.cs
- SqlCacheDependencySection.cs
- Zone.cs
- NameNode.cs
- TextDecorationLocationValidation.cs
- SpeechAudioFormatInfo.cs
- MappingSource.cs
- DLinqColumnProvider.cs
- Formatter.cs
- SID.cs
- WeakReference.cs
- PresentationAppDomainManager.cs
- PnrpPermission.cs
- CheckBox.cs
- BlurEffect.cs
- MenuRendererClassic.cs
- COM2IProvidePropertyBuilderHandler.cs
- XsltException.cs
- StringUtil.cs
- HttpListenerPrefixCollection.cs
- AnnotationMap.cs
- DispatchChannelSink.cs
- AccessedThroughPropertyAttribute.cs
- Facet.cs
- InternalRelationshipCollection.cs
- PerformanceCountersElement.cs
- ChtmlCommandAdapter.cs
- OperationCanceledException.cs
- WindowsFormsSynchronizationContext.cs
- OutputWindow.cs
- X500Name.cs
- IDQuery.cs
- ToolStripContentPanelRenderEventArgs.cs
- CachedFontFace.cs
- RijndaelManaged.cs
- ByteFacetDescriptionElement.cs
- UrlMapping.cs
- RegexMatch.cs
- BindingsCollection.cs
- TableCellCollection.cs
- SQLCharsStorage.cs
- EventLogLink.cs
- ReverseInheritProperty.cs
- linebase.cs
- RuntimeIdentifierPropertyAttribute.cs
- KnownBoxes.cs
- MemoryStream.cs
- BinaryMethodMessage.cs
- WebControlParameterProxy.cs
- DatagridviewDisplayedBandsData.cs
- AttributeSetAction.cs
- ObjectDataSourceEventArgs.cs
- EndpointDiscoveryMetadata11.cs
- CompilerTypeWithParams.cs
- GroupBoxRenderer.cs
- XmlSchemaAll.cs
- ResourceReader.cs
- CookielessHelper.cs
- VisualStyleInformation.cs
- BasicViewGenerator.cs
- ValueProviderWrapper.cs
- PaperSource.cs
- Rect.cs
- URIFormatException.cs
- ObjectKeyFrameCollection.cs
- CloudCollection.cs
- BinaryObjectWriter.cs
- FileUpload.cs
- SqlBulkCopyColumnMappingCollection.cs
- StorageAssociationTypeMapping.cs
- LogRecordSequence.cs
- AnimationTimeline.cs
- MsmqInputSessionChannel.cs
- DesignerActionService.cs
- mactripleDES.cs
- CollectionsUtil.cs
- ToolStripDropDownItem.cs
- MsmqTransportSecurity.cs
- AdjustableArrowCap.cs
- Point3DConverter.cs
- SingleConverter.cs
- ByteRangeDownloader.cs
- CommandExpr.cs
- EncoderFallback.cs
- SequentialActivityDesigner.cs
- KoreanLunisolarCalendar.cs
- LinqDataSourceContextData.cs
- WebPartsSection.cs
- WebPartEditorCancelVerb.cs
- DesignTimeTemplateParser.cs
- KeyedHashAlgorithm.cs
- VisualProxy.cs
- EncryptedPackage.cs
- KnownBoxes.cs
- ResourceContainer.cs
- GetWinFXPath.cs
- EmbeddedObject.cs
- NeutralResourcesLanguageAttribute.cs