File: Core\CSharp\MS\Internal\Automation\EventPropertyMap.cs
Project: wpf\src\PresentationCore.csproj (PresentationCore)
//---------------------------------------------------------------------------
//
// <copyright file="EventPropertyMap.cs" company="Microsoft">
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
//
// Description:
// Accessibility event map classes are used to determine if, and how many
// listeners there are for events and property changes.
//
// History:
//  07/23/2003 : BrendanM Ported to WCP
//
//---------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Windows;
using System.Diagnostics;
 
namespace MS.Internal.Automation
{
    // Manages the property map that is used to determine if there are
    // Automation clients interested in properties.
	internal class EventPropertyMap
	{
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
 
        #region Constructors
 
        // static class, private ctor to prevent creation
        private EventPropertyMap()
        {
        }
 
        #endregion Constructors
 
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        // Called during queueing of property change events to check if there are any
        // listeners that are interested in this property.  Returns true if there are
        // else false.  This function could be called frequently; it must be fast.
        internal static bool IsInterestingDP(DependencyProperty dp)
        {
            using (_propertyLock.ReadLock)
            {
                if (_propertyTable != null && _propertyTable.ContainsKey(dp))
                {
                    return true;
                }
            }
            return false;
        }
 
        // Updates the list of DynamicProperties that are currently being listened to.
        // Called by AccEvent class when certain events are added.
        //
        // Returns: true if the event property map was created during this call and
        //          false if the property map was not created during this call.
        internal static bool AddPropertyNotify(DependencyProperty [] properties)
        {
            if (properties == null)
                return false;
 
            bool createdMap = false;
            using (_propertyLock.WriteLock)
            {
                // If it doesn't exist, create the property map (key=dp value=listener count)
                if (_propertyTable == null)
                {
                    // Up to 20 properties before resize and
                    // small load factor optimizes for speed
                    _propertyTable = new Hashtable(20, .1f);
                    createdMap = true;
                }
 
                int cDPStart = _propertyTable.Count;
 
                // properties is an array of the properties one listener is interested in
                foreach (DependencyProperty dp in properties)
                {
                    if (dp == null)
                        continue;
 
                    int cDP = 0;
 
                    // If the property is in the table, increment it's count
                    if (_propertyTable.ContainsKey(dp))
                    {
                        cDP = (int)_propertyTable[dp];
                    }
 
                    cDP++;
                    _propertyTable[dp] = cDP;
                }
            }
 
            return createdMap;
        }
 
 
        // Updates the list of DynamicProperties that are currently being listened to.
        // Called by AccEvent class when removing certain events.
        // Returns: true if the property table is empty after this operation.
        internal static bool RemovePropertyNotify(DependencyProperty [] properties)
        {
            Debug.Assert(properties != null);
 
            bool isEmpty = false;
 
            using (_propertyLock.WriteLock)
            {
                if (_propertyTable != null)
                {
                    int cDPStart = _propertyTable.Count;
 
                    // properties is an array of the properties one listener is no longer interested in
                    foreach (DependencyProperty dp in properties)
                    {
                        if (_propertyTable.ContainsKey(dp))
                        {
                            int cDP = (int)_propertyTable[dp];
 
                            // Update or remove the entry based on remaining listeners
                            cDP--;
                            if (cDP > 0)
                            {
                                _propertyTable[dp] = cDP;
                            }
                            else
                            {
                                _propertyTable.Remove(dp);
                            }
                        }
                    }
 
                    // If there are no more properties in the map then delete it; the idea is if there
                    // are no listeners, don't make the property system do extra work.
                    if (_propertyTable.Count == 0)
                    {
                        _propertyTable = null;
                    }
                }
                isEmpty = (_propertyTable == null);
            }
 
            return isEmpty;
        }
 
        #endregion Internal Methods
 
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        #region Private Fields
 
        // static class, no instance data...
 
        private static ReaderWriterLockWrapper _propertyLock = new ReaderWriterLockWrapper();
        private static Hashtable _propertyTable;    // key=DP, data=listener count
 
        #endregion Private Fields
    }
}