Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / MS / Internal / WeakEventTable.cs / 1305600 / WeakEventTable.cs
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
// Description: Storage for the "weak event listener" pattern.
// See WeakEventManager.cs for an overview.
//
//---------------------------------------------------------------------------
using System;
using System.Diagnostics; // Debug
using System.Collections; // Hashtable
using System.Collections.Specialized; // HybridDictionary
using System.Runtime.CompilerServices; // RuntimeHelpers
using System.Security; // [SecurityCritical,SecurityTreatAsSafe]
using System.Threading; // [ThreadStatic]
using System.Windows; // WeakEventManager
using System.Windows.Threading; // DispatcherObject
using MS.Utility; // FrugalList
namespace MS.Internal
{
///
/// This class manages the correspondence between event types and
/// event managers, in support of the "weak event listener" pattern.
/// It also stores data on behalf of the managers; a manager can store
/// data of its own choosing, indexed by the pair (manager, source).
///
internal class WeakEventTable : DispatcherObject
{
#region Constructors
//
// Constructors
//
///
/// Create a new instance of WeakEventTable.
///
///
/// Critical: This code calls into Link demanded methods
/// (AppDomain.DomainUnload and AppDomain.ProcessExit) to attach handlers
/// TreatAsSafe: This code does not take any parameter or return state.
/// It simply attaches private call back.
///
[SecurityCritical,SecurityTreatAsSafe]
private WeakEventTable()
{
WeakEventTableShutDownListener listener = new WeakEventTableShutDownListener(this);
}
#endregion Constructors
#region Internal Properties
//
// Internal Properties
//
///
/// Return the WeakEventTable for the current thread
///
internal static WeakEventTable CurrentWeakEventTable
{
get
{
// _currentTable is [ThreadStatic], so there's one per thread
if (_currentTable == null)
{
_currentTable = new WeakEventTable();
}
return _currentTable;
}
}
///
/// Take a read-lock on the table, and return the IDisposable.
/// Queries to the table should occur within a
/// "using (Table.ReadLock) { ... }" clause, except for queries
/// that are already within a write lock.
///
internal IDisposable ReadLock
{
get { return _lock.ReadLock; }
}
///
/// Take a write-lock on the table, and return the IDisposable.
/// All modifications to the table should occur within a
/// "using (Table.WriteLock) { ... }" clause.
///
internal IDisposable WriteLock
{
get { return _lock.WriteLock; }
}
///
/// Get or set the manager instance for the given type.
///
internal WeakEventManager this[Type managerType]
{
get { return (WeakEventManager)_managerTable[managerType]; }
set { _managerTable[managerType] = value; }
}
///
/// Get or set the data stored by the given manager for the given source.
///
internal object this[WeakEventManager manager, object source]
{
get
{
EventKey key = new EventKey(manager, source);
object result = _dataTable[key];
return result;
}
set
{
EventKey key = new EventKey(manager, source, true);
_dataTable[key] = value;
}
}
///
/// Indicates whether cleanup is enabled.
///
///
/// Normally cleanup is always enabled, but a perf test environment might
/// want to disable cleanup so that it doesn't interfere with the real
/// perf measurements.
///
internal bool IsCleanupEnabled
{
get { return _cleanupEnabled; }
set { _cleanupEnabled = value; }
}
#endregion Internal Properties
#region Internal Methods
//
// Internal Methods
//
///
/// Remove the data for the given manager and source.
///
internal void Remove(WeakEventManager manager, object source)
{
EventKey key = new EventKey(manager, source);
_dataTable.Remove(key);
}
///
/// Schedule a cleanup pass. This can be called from any thread.
///
internal void ScheduleCleanup()
{
// only the first request after a previous cleanup should schedule real work
if (Interlocked.Increment(ref _cleanupRequests) == 1)
{
Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new DispatcherOperationCallback(CleanupOperation), null);
}
}
///
/// Perform a cleanup pass.
///
internal static bool Cleanup()
{
return CurrentWeakEventTable.Purge(false);
}
#endregion Internal Methods
#region Private Methods
//
// Private Methods
//
// run a cleanup pass
private object CleanupOperation(object arg)
{
// allow new requests, even if cleanup is disabled
Interlocked.Exchange(ref _cleanupRequests, 0);
if (IsCleanupEnabled)
{
Purge(false);
}
return null;
}
// remove dead entries. When purgeAll is true, remove all entries.
private bool Purge(bool purgeAll)
{
bool foundDirt = false;
using (this.WriteLock)
{
// copy the keys into a separate array, so that later on
// we can change the table while iterating over the keys
ICollection ic = _dataTable.Keys;
EventKey[] keys = new EventKey[ic.Count];
ic.CopyTo(keys, 0);
for (int i=keys.Length-1; i>=0; --i)
{
object source = keys[i].Source;
foundDirt |= keys[i].Manager.PurgeInternal(source, _dataTable[keys[i]], purgeAll);
// if source has been GC'd, remove its data
if (!purgeAll && source == null)
{
_dataTable.Remove(keys[i]);
}
}
if (purgeAll)
{
_managerTable.Clear();
_dataTable.Clear();
}
}
return foundDirt;
}
// do the final cleanup when the Dispatcher or AppDomain is shut down
private void OnShutDown()
{
Purge(true);
// remove the table from thread storage
_currentTable = null;
}
#endregion Private Methods
#region Private Fields
//
// Private Fields
//
private Hashtable _managerTable = new Hashtable(); // maps manager type -> instance
private Hashtable _dataTable = new Hashtable(); // maps EventKey -> data
ReaderWriterLockWrapper _lock = new ReaderWriterLockWrapper();
private int _cleanupRequests;
private bool _cleanupEnabled = true;
[ThreadStatic]
private static WeakEventTable _currentTable; // one table per thread
#endregion Private Fields
#region WeakEventTableShutDownListener
private sealed class WeakEventTableShutDownListener : ShutDownListener
{
///
/// Critical: accesses AppDomain.DomainUnload event
/// TreatAsSafe: This code does not take any parameter or return state.
/// It simply attaches private callbacks.
///
[SecurityCritical,SecurityTreatAsSafe]
public WeakEventTableShutDownListener(WeakEventTable target) : base(target)
{
}
internal override void OnShutDown(object target, object sender, EventArgs e)
{
WeakEventTable table = (WeakEventTable)target;
table.OnShutDown();
}
}
#endregion WeakEventTableShutDownListener
#region Table Keys
// the key for the data table:
private struct EventKey
{
internal EventKey(WeakEventManager manager, object source, bool useWeakRef)
{
_manager = manager;
_source = new WeakReference(source);
_hashcode = unchecked(manager.GetHashCode() + RuntimeHelpers.GetHashCode(source));
}
internal EventKey(WeakEventManager manager, object source)
{
_manager = manager;
_source = source;
_hashcode = unchecked(manager.GetHashCode() + RuntimeHelpers.GetHashCode(source));
}
internal object Source
{
get { return ((WeakReference)_source).Target; }
}
internal WeakEventManager Manager
{
get { return _manager; }
}
public override int GetHashCode()
{
#if DEBUG
WeakReference wr = _source as WeakReference;
object source = (wr != null) ? wr.Target : _source;
if (source != null)
{
int hashcode = unchecked(_manager.GetHashCode() + RuntimeHelpers.GetHashCode(source));
Debug.Assert(hashcode == _hashcode, "hashcodes disagree");
}
#endif
return _hashcode;
}
public override bool Equals(object o)
{
if (o is EventKey)
{
WeakReference wr;
EventKey ek = (EventKey)o;
if (_manager != ek._manager || _hashcode != ek._hashcode)
return false;
wr = this._source as WeakReference;
object s1 = (wr != null) ? wr.Target : this._source;
wr = ek._source as WeakReference;
object s2 = (wr != null) ? wr.Target : ek._source;
if (s1!=null && s2!=null)
return (s1 == s2);
else
return (_source == ek._source);
}
else
{
return false;
}
}
public static bool operator==(EventKey key1, EventKey key2)
{
return key1.Equals(key2);
}
public static bool operator!=(EventKey key1, EventKey key2)
{
return !key1.Equals(key2);
}
WeakEventManager _manager;
object _source; // lookup: direct ref; In table: WeakRef
int _hashcode; // cached, in case source is GC'd
}
#endregion Table Keys
}
}
// 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: Storage for the "weak event listener" pattern.
// See WeakEventManager.cs for an overview.
//
//---------------------------------------------------------------------------
using System;
using System.Diagnostics; // Debug
using System.Collections; // Hashtable
using System.Collections.Specialized; // HybridDictionary
using System.Runtime.CompilerServices; // RuntimeHelpers
using System.Security; // [SecurityCritical,SecurityTreatAsSafe]
using System.Threading; // [ThreadStatic]
using System.Windows; // WeakEventManager
using System.Windows.Threading; // DispatcherObject
using MS.Utility; // FrugalList
namespace MS.Internal
{
///
/// This class manages the correspondence between event types and
/// event managers, in support of the "weak event listener" pattern.
/// It also stores data on behalf of the managers; a manager can store
/// data of its own choosing, indexed by the pair (manager, source).
///
internal class WeakEventTable : DispatcherObject
{
#region Constructors
//
// Constructors
//
///
/// Create a new instance of WeakEventTable.
///
///
/// Critical: This code calls into Link demanded methods
/// (AppDomain.DomainUnload and AppDomain.ProcessExit) to attach handlers
/// TreatAsSafe: This code does not take any parameter or return state.
/// It simply attaches private call back.
///
[SecurityCritical,SecurityTreatAsSafe]
private WeakEventTable()
{
WeakEventTableShutDownListener listener = new WeakEventTableShutDownListener(this);
}
#endregion Constructors
#region Internal Properties
//
// Internal Properties
//
///
/// Return the WeakEventTable for the current thread
///
internal static WeakEventTable CurrentWeakEventTable
{
get
{
// _currentTable is [ThreadStatic], so there's one per thread
if (_currentTable == null)
{
_currentTable = new WeakEventTable();
}
return _currentTable;
}
}
///
/// Take a read-lock on the table, and return the IDisposable.
/// Queries to the table should occur within a
/// "using (Table.ReadLock) { ... }" clause, except for queries
/// that are already within a write lock.
///
internal IDisposable ReadLock
{
get { return _lock.ReadLock; }
}
///
/// Take a write-lock on the table, and return the IDisposable.
/// All modifications to the table should occur within a
/// "using (Table.WriteLock) { ... }" clause.
///
internal IDisposable WriteLock
{
get { return _lock.WriteLock; }
}
///
/// Get or set the manager instance for the given type.
///
internal WeakEventManager this[Type managerType]
{
get { return (WeakEventManager)_managerTable[managerType]; }
set { _managerTable[managerType] = value; }
}
///
/// Get or set the data stored by the given manager for the given source.
///
internal object this[WeakEventManager manager, object source]
{
get
{
EventKey key = new EventKey(manager, source);
object result = _dataTable[key];
return result;
}
set
{
EventKey key = new EventKey(manager, source, true);
_dataTable[key] = value;
}
}
///
/// Indicates whether cleanup is enabled.
///
///
/// Normally cleanup is always enabled, but a perf test environment might
/// want to disable cleanup so that it doesn't interfere with the real
/// perf measurements.
///
internal bool IsCleanupEnabled
{
get { return _cleanupEnabled; }
set { _cleanupEnabled = value; }
}
#endregion Internal Properties
#region Internal Methods
//
// Internal Methods
//
///
/// Remove the data for the given manager and source.
///
internal void Remove(WeakEventManager manager, object source)
{
EventKey key = new EventKey(manager, source);
_dataTable.Remove(key);
}
///
/// Schedule a cleanup pass. This can be called from any thread.
///
internal void ScheduleCleanup()
{
// only the first request after a previous cleanup should schedule real work
if (Interlocked.Increment(ref _cleanupRequests) == 1)
{
Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new DispatcherOperationCallback(CleanupOperation), null);
}
}
///
/// Perform a cleanup pass.
///
internal static bool Cleanup()
{
return CurrentWeakEventTable.Purge(false);
}
#endregion Internal Methods
#region Private Methods
//
// Private Methods
//
// run a cleanup pass
private object CleanupOperation(object arg)
{
// allow new requests, even if cleanup is disabled
Interlocked.Exchange(ref _cleanupRequests, 0);
if (IsCleanupEnabled)
{
Purge(false);
}
return null;
}
// remove dead entries. When purgeAll is true, remove all entries.
private bool Purge(bool purgeAll)
{
bool foundDirt = false;
using (this.WriteLock)
{
// copy the keys into a separate array, so that later on
// we can change the table while iterating over the keys
ICollection ic = _dataTable.Keys;
EventKey[] keys = new EventKey[ic.Count];
ic.CopyTo(keys, 0);
for (int i=keys.Length-1; i>=0; --i)
{
object source = keys[i].Source;
foundDirt |= keys[i].Manager.PurgeInternal(source, _dataTable[keys[i]], purgeAll);
// if source has been GC'd, remove its data
if (!purgeAll && source == null)
{
_dataTable.Remove(keys[i]);
}
}
if (purgeAll)
{
_managerTable.Clear();
_dataTable.Clear();
}
}
return foundDirt;
}
// do the final cleanup when the Dispatcher or AppDomain is shut down
private void OnShutDown()
{
Purge(true);
// remove the table from thread storage
_currentTable = null;
}
#endregion Private Methods
#region Private Fields
//
// Private Fields
//
private Hashtable _managerTable = new Hashtable(); // maps manager type -> instance
private Hashtable _dataTable = new Hashtable(); // maps EventKey -> data
ReaderWriterLockWrapper _lock = new ReaderWriterLockWrapper();
private int _cleanupRequests;
private bool _cleanupEnabled = true;
[ThreadStatic]
private static WeakEventTable _currentTable; // one table per thread
#endregion Private Fields
#region WeakEventTableShutDownListener
private sealed class WeakEventTableShutDownListener : ShutDownListener
{
///
/// Critical: accesses AppDomain.DomainUnload event
/// TreatAsSafe: This code does not take any parameter or return state.
/// It simply attaches private callbacks.
///
[SecurityCritical,SecurityTreatAsSafe]
public WeakEventTableShutDownListener(WeakEventTable target) : base(target)
{
}
internal override void OnShutDown(object target, object sender, EventArgs e)
{
WeakEventTable table = (WeakEventTable)target;
table.OnShutDown();
}
}
#endregion WeakEventTableShutDownListener
#region Table Keys
// the key for the data table:
private struct EventKey
{
internal EventKey(WeakEventManager manager, object source, bool useWeakRef)
{
_manager = manager;
_source = new WeakReference(source);
_hashcode = unchecked(manager.GetHashCode() + RuntimeHelpers.GetHashCode(source));
}
internal EventKey(WeakEventManager manager, object source)
{
_manager = manager;
_source = source;
_hashcode = unchecked(manager.GetHashCode() + RuntimeHelpers.GetHashCode(source));
}
internal object Source
{
get { return ((WeakReference)_source).Target; }
}
internal WeakEventManager Manager
{
get { return _manager; }
}
public override int GetHashCode()
{
#if DEBUG
WeakReference wr = _source as WeakReference;
object source = (wr != null) ? wr.Target : _source;
if (source != null)
{
int hashcode = unchecked(_manager.GetHashCode() + RuntimeHelpers.GetHashCode(source));
Debug.Assert(hashcode == _hashcode, "hashcodes disagree");
}
#endif
return _hashcode;
}
public override bool Equals(object o)
{
if (o is EventKey)
{
WeakReference wr;
EventKey ek = (EventKey)o;
if (_manager != ek._manager || _hashcode != ek._hashcode)
return false;
wr = this._source as WeakReference;
object s1 = (wr != null) ? wr.Target : this._source;
wr = ek._source as WeakReference;
object s2 = (wr != null) ? wr.Target : ek._source;
if (s1!=null && s2!=null)
return (s1 == s2);
else
return (_source == ek._source);
}
else
{
return false;
}
}
public static bool operator==(EventKey key1, EventKey key2)
{
return key1.Equals(key2);
}
public static bool operator!=(EventKey key1, EventKey key2)
{
return !key1.Equals(key2);
}
WeakEventManager _manager;
object _source; // lookup: direct ref; In table: WeakRef
int _hashcode; // cached, in case source is GC'd
}
#endregion Table Keys
}
}
// 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
- Journal.cs
- MemoryStream.cs
- MimeWriter.cs
- OutOfMemoryException.cs
- XsdValidatingReader.cs
- CellCreator.cs
- DesignBindingPropertyDescriptor.cs
- ViewGenResults.cs
- CodeExpressionRuleDeclaration.cs
- SerialReceived.cs
- AttachedPropertyBrowsableAttribute.cs
- WebConfigManager.cs
- ReadOnlyDictionary.cs
- BulletedList.cs
- SQLResource.cs
- ReliableMessagingVersionConverter.cs
- WebPartDescriptionCollection.cs
- EntityModelBuildProvider.cs
- AppSettingsExpressionBuilder.cs
- DataGridViewLinkColumn.cs
- EncodingStreamWrapper.cs
- BamlWriter.cs
- ViewStateModeByIdAttribute.cs
- BaseParser.cs
- HScrollBar.cs
- ProcessHostMapPath.cs
- HashStream.cs
- RuleProcessor.cs
- DynamicDataExtensions.cs
- SystemDiagnosticsSection.cs
- PageSettings.cs
- M3DUtil.cs
- NativeWindow.cs
- XmlSchemaDocumentation.cs
- PaperSize.cs
- AnnotationDocumentPaginator.cs
- DbReferenceCollection.cs
- HttpApplicationFactory.cs
- BuildTopDownAttribute.cs
- Cloud.cs
- GlyphsSerializer.cs
- LinkConverter.cs
- UniqueIdentifierService.cs
- PermissionListSet.cs
- ConfigurationSectionCollection.cs
- LazyLoadBehavior.cs
- StateRuntime.cs
- HitTestParameters.cs
- WebPartZoneCollection.cs
- EpmCustomContentWriterNodeData.cs
- XmlSchemaObjectTable.cs
- TableDetailsCollection.cs
- SynchronizedPool.cs
- TemplateKeyConverter.cs
- TreeNodeMouseHoverEvent.cs
- FrameworkElementAutomationPeer.cs
- TreeNodeClickEventArgs.cs
- ShapingEngine.cs
- EventManager.cs
- BackStopAuthenticationModule.cs
- ConnectionsZone.cs
- ProxyGenerationError.cs
- ValueUtilsSmi.cs
- SchemaElement.cs
- TransactionFilter.cs
- EdmToObjectNamespaceMap.cs
- FixedFlowMap.cs
- PrimaryKeyTypeConverter.cs
- TreeNodeBindingCollection.cs
- DoubleAnimationUsingPath.cs
- RadioButton.cs
- Ref.cs
- HebrewCalendar.cs
- ToolStripRenderer.cs
- RC2CryptoServiceProvider.cs
- AsymmetricKeyExchangeFormatter.cs
- BitSet.cs
- OdbcConnectionPoolProviderInfo.cs
- HttpCookieCollection.cs
- WorkflowApplication.cs
- PopupControlService.cs
- HttpException.cs
- UnknownWrapper.cs
- WorkflowItemsPresenter.cs
- XmlDocumentSerializer.cs
- DataGridViewTextBoxCell.cs
- DataStreamFromComStream.cs
- ACE.cs
- BamlBinaryWriter.cs
- ArraySet.cs
- DataGridDetailsPresenter.cs
- BuildProviderCollection.cs
- OleServicesContext.cs
- BitmapEffectCollection.cs
- ScriptReferenceBase.cs
- RightsManagementEncryptionTransform.cs
- SecuritySessionSecurityTokenAuthenticator.cs
- unsafeIndexingFilterStream.cs
- ScriptingJsonSerializationSection.cs
- TargetException.cs