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
- DependencyObjectType.cs
- GB18030Encoding.cs
- WebControlParameterProxy.cs
- RectIndependentAnimationStorage.cs
- XPathNavigatorKeyComparer.cs
- SyntaxCheck.cs
- _SslSessionsCache.cs
- ProxyHwnd.cs
- RawUIStateInputReport.cs
- ProcessInfo.cs
- CheckBoxStandardAdapter.cs
- RangeValuePatternIdentifiers.cs
- DecoderNLS.cs
- ProxyAttribute.cs
- InvalidChannelBindingException.cs
- FilterableAttribute.cs
- TextRange.cs
- BindingCollection.cs
- SiteOfOriginContainer.cs
- SupportingTokenAuthenticatorSpecification.cs
- WebPartEditorOkVerb.cs
- ElementUtil.cs
- DisplayInformation.cs
- LocalIdKeyIdentifierClause.cs
- ViewManagerAttribute.cs
- LinqDataView.cs
- ColumnMapProcessor.cs
- PointHitTestResult.cs
- WebPartEditVerb.cs
- InputProcessorProfiles.cs
- KnownTypesProvider.cs
- DictionaryContent.cs
- StoragePropertyMapping.cs
- PopupEventArgs.cs
- HttpListenerContext.cs
- XmlSerializerFactory.cs
- Scheduler.cs
- CreateUserErrorEventArgs.cs
- PanelStyle.cs
- UrlMappingsSection.cs
- MessageLogTraceRecord.cs
- SrgsGrammar.cs
- AxisAngleRotation3D.cs
- String.cs
- ADMembershipUser.cs
- AdornedElementPlaceholder.cs
- SHA384Managed.cs
- ObjectQuery.cs
- CodeSnippetStatement.cs
- ExecutionEngineException.cs
- EntityParameterCollection.cs
- CurrencyWrapper.cs
- ProcessHostMapPath.cs
- DbFunctionCommandTree.cs
- XamlTypeMapper.cs
- DefaultMemberAttribute.cs
- EncryptedType.cs
- EntityViewGenerationConstants.cs
- _Events.cs
- ActivityTypeDesigner.xaml.cs
- XmlUtf8RawTextWriter.cs
- CryptoApi.cs
- MissingMemberException.cs
- TextRangeEditLists.cs
- SRDisplayNameAttribute.cs
- OrderingQueryOperator.cs
- ElementsClipboardData.cs
- complextypematerializer.cs
- DataGridViewComboBoxColumn.cs
- MemberPath.cs
- SwitchDesigner.xaml.cs
- JoinElimination.cs
- ItemsPanelTemplate.cs
- PerformanceCounterCategory.cs
- InfocardClientCredentials.cs
- StubHelpers.cs
- LinkClickEvent.cs
- CustomCategoryAttribute.cs
- BitStack.cs
- XmlImplementation.cs
- WorkflowElementDialog.cs
- ButtonField.cs
- PrimaryKeyTypeConverter.cs
- Stackframe.cs
- LabelExpression.cs
- WindowsToolbarItemAsMenuItem.cs
- GridLength.cs
- PersonalizationProviderHelper.cs
- panel.cs
- OptimizerPatterns.cs
- RankException.cs
- InputElement.cs
- DataGridViewRowConverter.cs
- SqlException.cs
- MouseGesture.cs
- DbTransaction.cs
- ImageButton.cs
- _NegoState.cs
- VersionPair.cs
- Brush.cs