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
- DataSourceControl.cs
- _ListenerResponseStream.cs
- ConvertBinder.cs
- UserControlFileEditor.cs
- FileDetails.cs
- DictionaryEntry.cs
- LocationReferenceEnvironment.cs
- Emitter.cs
- QuadraticBezierSegment.cs
- Console.cs
- GridViewColumn.cs
- Activator.cs
- HtmlWindow.cs
- PropertyChangedEventArgs.cs
- TraceListener.cs
- SByteStorage.cs
- AssertHelper.cs
- EntityCommand.cs
- ServiceHostingEnvironment.cs
- CodeDirectionExpression.cs
- EntityDataSourceWrapperCollection.cs
- WebDescriptionAttribute.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- TakeOrSkipQueryOperator.cs
- PartitionResolver.cs
- GuidelineCollection.cs
- DataGridViewUtilities.cs
- HttpHandlersInstallComponent.cs
- DecoderFallback.cs
- StringDictionary.cs
- ParallelLoopState.cs
- MaskedTextBoxDesigner.cs
- DataGridItemCollection.cs
- ConnectionProviderAttribute.cs
- HtmlUtf8RawTextWriter.cs
- NativeRecognizer.cs
- XmlSchemaAttributeGroupRef.cs
- Attributes.cs
- BindingCompleteEventArgs.cs
- SimpleWorkerRequest.cs
- Literal.cs
- ArcSegment.cs
- ServiceModelPerformanceCounters.cs
- TagPrefixAttribute.cs
- ProviderConnectionPoint.cs
- VariableAction.cs
- _ServiceNameStore.cs
- FixedDocumentSequencePaginator.cs
- SoapDocumentMethodAttribute.cs
- NativeCppClassAttribute.cs
- NotConverter.cs
- RoleManagerSection.cs
- PriorityQueue.cs
- MimeTextImporter.cs
- cookiecollection.cs
- MobileControlsSectionHandler.cs
- PassportIdentity.cs
- PasswordRecovery.cs
- TextElementEnumerator.cs
- DataGridViewCheckBoxColumn.cs
- ToolStripLocationCancelEventArgs.cs
- ImageDrawing.cs
- ObjectManager.cs
- RequestCacheManager.cs
- CompiledELinqQueryState.cs
- TextEncodedRawTextWriter.cs
- ObjRef.cs
- ZipIOBlockManager.cs
- AsyncCompletedEventArgs.cs
- TcpClientSocketManager.cs
- DESCryptoServiceProvider.cs
- InitializerFacet.cs
- Empty.cs
- CommandDesigner.cs
- ValueQuery.cs
- Automation.cs
- QilFactory.cs
- DivideByZeroException.cs
- FileAuthorizationModule.cs
- CollectionConverter.cs
- SHA256.cs
- InternalConfigRoot.cs
- InkCanvasSelectionAdorner.cs
- RegexStringValidatorAttribute.cs
- GridViewAutomationPeer.cs
- TreeViewBindingsEditor.cs
- XhtmlBasicSelectionListAdapter.cs
- DecoderNLS.cs
- ADRoleFactory.cs
- AmbiguousMatchException.cs
- TemplatedControlDesigner.cs
- DocumentOrderComparer.cs
- WorkflowTerminatedException.cs
- AutomationTextAttribute.cs
- DataGridViewRow.cs
- MetadataAssemblyHelper.cs
- UnicastIPAddressInformationCollection.cs
- SecurityDescriptor.cs
- MobileControlsSection.cs
- CompositeControl.cs