File: Core\CSharp\System\Windows\Media\UniqueEventHelper.cs
Project: wpf\src\PresentationCore.csproj (PresentationCore)
using System;
using System.Collections;
using System.Diagnostics;
 
namespace System.Windows.Media
{
    /// <summary>
    /// Aids in making events unique. i.e. you register the same function for
    /// the same event twice, but it will only be called once for each time
    /// the event is invoked.
    ///
    /// UniqueEventHelper should only be accessed from the UI thread so that
    /// handlers that throw exceptions will crash the app, making the developer
    /// aware of the problem.
    /// </summary>
    internal class UniqueEventHelper<TEventArgs>
            where TEventArgs : EventArgs
    {
        /// <summary>
        /// Add the handler to the list of handlers associated with this event.
        /// If the handler has already been added, we simply increment the ref
        /// count. That way if this same handler has already been added, it
        /// won't be invoked multiple times when the event is raised.
        /// </summary>
        internal void AddEvent(EventHandler<TEventArgs> handler)
        {
            if (handler == null)
            {
                throw new System.ArgumentNullException("handler");
            }
 
            EnsureEventTable();
 
            if (_htDelegates[handler] == null)
            {
                _htDelegates.Add(handler, 1);
            }
            else
            {
                int refCount = (int)_htDelegates[handler] + 1;
                _htDelegates[handler] = refCount;
            }
        }
 
        /// <summary>
        /// Removed the handler from the list of handlers associated with this
        /// event. If the handler has been added multiple times (more times than
        /// it has been removed), we simply decrement its ref count.
        /// </summary>
        internal void RemoveEvent(EventHandler<TEventArgs> handler)
        {
            if (handler == null)
            {
                throw new System.ArgumentNullException("handler");
            }
 
            EnsureEventTable();
 
            if (_htDelegates[handler] != null)
            {
                int refCount = (int)_htDelegates[handler];
 
                if (refCount == 1)
                {
                    _htDelegates.Remove(handler);
                }
                else
                {
                    _htDelegates[handler] = refCount - 1;
                }
            }
        }
 
        /// <summary>
        /// Enumerates all the keys in the hashtable, which must be EventHandlers,
        /// and invokes them.
        /// </summary>
        /// <param name="sender">The sender for the callback.</param>
        /// <param name="args">The args object to be sent by the delegate</param>
        internal void InvokeEvents(object sender, TEventArgs args)
        {
            Debug.Assert((sender != null), "Sender is null");
 
            if (_htDelegates != null)
            {
                Hashtable htDelegates = (Hashtable)_htDelegates.Clone();
                foreach (EventHandler<TEventArgs> handler in htDelegates.Keys)
                {
                    Debug.Assert((handler != null), "Event handler is null");
                    handler(sender, args);
                }
            }
        }
 
        /// <summary>
        /// Clones the event helper
        /// </summary>
        internal UniqueEventHelper<TEventArgs> Clone()
        {
            UniqueEventHelper<TEventArgs> ueh = new UniqueEventHelper<TEventArgs>();
            if (_htDelegates != null)
            {
                ueh._htDelegates = (Hashtable)_htDelegates.Clone();
            }
            return ueh;
        }
 
        /// <summary>
        /// Ensures Hashtable is created so that event handlers can be added/removed
        /// </summary>
        private void EnsureEventTable()
        {
            if (_htDelegates == null)
            {
                _htDelegates = new Hashtable();
            }
        }
 
        private Hashtable _htDelegates;
    }
 
 
 
    // 
 
 
 
    internal class UniqueEventHelper
    {
        /// <summary>
        /// Add the handler to the list of handlers associated with this event.
        /// If the handler has already been added, we simply increment the ref
        /// count. That way if this same handler has already been added, it
        /// won't be invoked multiple times when the event is raised.
        /// </summary>
        internal void AddEvent(EventHandler handler)
        {
            if (handler == null)
            {
                throw new System.ArgumentNullException("handler");
            }
 
            EnsureEventTable();
 
            if (_htDelegates[handler] == null)
            {
                _htDelegates.Add(handler, 1);
            }
            else
            {
                int refCount = (int)_htDelegates[handler] + 1;
                _htDelegates[handler] = refCount;
            }
        }
 
        /// <summary>
        /// Removed the handler from the list of handlers associated with this
        /// event. If the handler has been added multiple times (more times than
        /// it has been removed), we simply decrement its ref count.
        /// </summary>
        internal void RemoveEvent(EventHandler handler)
        {
            if (handler == null)
            {
                throw new System.ArgumentNullException("handler");
            }
 
            EnsureEventTable();
 
            if (_htDelegates[handler] != null)
            {
                int refCount = (int)_htDelegates[handler];
 
                if (refCount == 1)
                {
                    _htDelegates.Remove(handler);
                }
                else
                {
                    _htDelegates[handler] = refCount - 1;
                }
            }
        }
 
        /// <summary>
        /// Enumerates all the keys in the hashtable, which must be EventHandlers,
        /// and invokes them.
        /// </summary>
        /// <param name="sender">The sender for the callback.</param>
        /// <param name="args">The args object to be sent by the delegate</param>
        internal void InvokeEvents(object sender, EventArgs args)
        {
            Debug.Assert((sender != null), "Sender is null");
 
            if (_htDelegates != null)
            {
                Hashtable htDelegates = (Hashtable)_htDelegates.Clone();
                foreach (EventHandler handler in htDelegates.Keys)
                {
                    Debug.Assert((handler != null), "Event handler is null");
                    handler(sender, args);
                }
            }
        }
 
        /// <summary>
        /// Clones the event helper
        /// </summary>
        internal UniqueEventHelper Clone()
        {
            UniqueEventHelper ueh = new UniqueEventHelper();
            if (_htDelegates != null)
            {
                ueh._htDelegates = (Hashtable)_htDelegates.Clone();
            }
            return ueh;
        }
 
        /// <summary>
        /// Ensures Hashtable is created so that event handlers can be added/removed
        /// </summary>
        private void EnsureEventTable()
        {
            if (_htDelegates == null)
            {
                _htDelegates = new Hashtable();
            }
        }
 
        private Hashtable _htDelegates;
    }
}