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
- UnsupportedPolicyOptionsException.cs
- InvokeDelegate.cs
- FormViewPagerRow.cs
- FilterElement.cs
- WinCategoryAttribute.cs
- BitmapEffectrendercontext.cs
- Int16AnimationUsingKeyFrames.cs
- CustomBindingElementCollection.cs
- ReferencedType.cs
- ByteRangeDownloader.cs
- GridViewColumnHeaderAutomationPeer.cs
- RandomDelayQueuedSendsAsyncResult.cs
- SystemWebCachingSectionGroup.cs
- PublishLicense.cs
- NameValuePair.cs
- SingleObjectCollection.cs
- UnsignedPublishLicense.cs
- TokenBasedSetEnumerator.cs
- ObfuscationAttribute.cs
- ScaleTransform.cs
- XsltContext.cs
- CommonRemoteMemoryBlock.cs
- COM2Properties.cs
- EFColumnProvider.cs
- ProviderBase.cs
- ReadOnlyHierarchicalDataSourceView.cs
- WorkflowDurableInstance.cs
- BindingContext.cs
- SrgsGrammarCompiler.cs
- PageAsyncTaskManager.cs
- PrintPreviewDialog.cs
- DataGridViewComboBoxEditingControl.cs
- XmlDataSourceView.cs
- ItemCheckEvent.cs
- StorageComplexTypeMapping.cs
- Frame.cs
- MethodBuilder.cs
- SoapAttributes.cs
- VersionedStream.cs
- PrintPreviewControl.cs
- SelectorAutomationPeer.cs
- SQLCharsStorage.cs
- SmtpFailedRecipientsException.cs
- TimeoutException.cs
- ListDictionaryInternal.cs
- Cloud.cs
- CompositeTypefaceMetrics.cs
- ServiceDescriptions.cs
- MetadataArtifactLoaderFile.cs
- TimeSpanSecondsOrInfiniteConverter.cs
- EntityDataSourceChangingEventArgs.cs
- OverrideMode.cs
- CorrelationManager.cs
- ApplicationDirectoryMembershipCondition.cs
- BoundingRectTracker.cs
- ExpressionHelper.cs
- RequiredAttributeAttribute.cs
- X509Certificate2.cs
- EntityDataSourceWrapperCollection.cs
- SerializationSectionGroup.cs
- CategoryAttribute.cs
- TextContainer.cs
- CngUIPolicy.cs
- AdapterDictionary.cs
- RootDesignerSerializerAttribute.cs
- Queue.cs
- TypeConverterHelper.cs
- Ticks.cs
- GeneratedContractType.cs
- DesignerToolboxInfo.cs
- NullableDoubleAverageAggregationOperator.cs
- IInstanceContextProvider.cs
- SoapHeader.cs
- WebPermission.cs
- MailWebEventProvider.cs
- mansign.cs
- ReferenceEqualityComparer.cs
- HelpPage.cs
- DictionaryBase.cs
- CopyAction.cs
- ListBindingHelper.cs
- BitmapEffect.cs
- RightsManagementEncryptedStream.cs
- CacheModeValueSerializer.cs
- ResetableIterator.cs
- SequenceDesignerAccessibleObject.cs
- ThreadStaticAttribute.cs
- DataMisalignedException.cs
- AnimatedTypeHelpers.cs
- TileModeValidation.cs
- WindowsGraphicsWrapper.cs
- XsltConvert.cs
- BamlLocalizableResource.cs
- IFlowDocumentViewer.cs
- compensatingcollection.cs
- Cursor.cs
- WebInvokeAttribute.cs
- ProviderIncompatibleException.cs
- FontInfo.cs
- PixelFormatConverter.cs