| File: System\Windows\EventHandlersStore.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationCore\PresentationCore.csproj (PresentationCore) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using MS.Utility; namespace System.Windows { /// <summary> /// Container for the event handlers /// </summary> /// <remarks> /// EventHandlersStore is a hashtable /// of handlers for a given /// EventPrivateKey or RoutedEvent /// </remarks> internal class EventHandlersStore { #region Construction /// <summary> /// Constructor for EventHandlersStore /// </summary> public EventHandlersStore() { _entries = new FrugalMap(); } /// <summary> /// Copy constructor for EventHandlersStore /// </summary> public EventHandlersStore(EventHandlersStore source) { _entries = source._entries; } #endregion Construction #region ExternalAPI /// <summary> /// Adds a Clr event handler for the /// given EventPrivateKey to the store /// </summary> /// <param name="key"> /// Private key for the event /// </param> /// <param name="handler"> /// Event handler /// </param> public void Add(EventPrivateKey key, Delegate handler) { ArgumentNullException.ThrowIfNull(key); ArgumentNullException.ThrowIfNull(handler); // Get the entry corresponding to the given key Delegate existingDelegate = (Delegate)this[key]; if (existingDelegate == null) { _entries[key.GlobalIndex] = handler; } else { _entries[key.GlobalIndex] = Delegate.Combine(existingDelegate, handler); } } /// <summary> /// Removes an instance of the specified /// Clr event handler for the given /// EventPrivateKey from the store /// </summary> /// <param name="key"> /// Private key for the event /// </param> /// <param name="handler"> /// Event handler /// </param> /// <remarks> /// NOTE: This method does nothing if no /// matching handler instances are found /// in the store /// </remarks> public void Remove(EventPrivateKey key, Delegate handler) { ArgumentNullException.ThrowIfNull(key); ArgumentNullException.ThrowIfNull(handler); // Get the entry corresponding to the given key Delegate existingDelegate = (Delegate) this[key]; if (existingDelegate != null) { existingDelegate = Delegate.Remove(existingDelegate, handler); if (existingDelegate == null) { // last handler for this event was removed -- reclaim space in // underlying FrugalMap by setting value to DependencyProperty.UnsetValue _entries[key.GlobalIndex] = DependencyProperty.UnsetValue; } else { _entries[key.GlobalIndex] = existingDelegate; } } } /// <summary> /// Gets all the handlers for the given EventPrivateKey /// </summary> /// <param name="key"> /// Private key for the event /// </param> /// <returns> /// Combined delegate or null if no match found /// </returns> /// <remarks> /// This method is not exposing a security risk for the reason /// that the EventPrivateKey for the events will themselves be /// private to the declaring class. This will be enforced via fxcop rules. /// </remarks> public Delegate Get(EventPrivateKey key) { ArgumentNullException.ThrowIfNull(key); // Return the handlers corresponding to the given key return (Delegate)this[key]; } #endregion ExternalAPI #region Operations /// <summary> /// Adds a routed event handler for the given /// RoutedEvent to the store /// </summary> public void AddRoutedEventHandler( RoutedEvent routedEvent, Delegate handler, bool handledEventsToo) { ArgumentNullException.ThrowIfNull(routedEvent); ArgumentNullException.ThrowIfNull(handler); if (!routedEvent.IsLegalHandler(handler)) { throw new ArgumentException(SR.HandlerTypeIllegal); } // Create a new RoutedEventHandler RoutedEventHandlerInfo routedEventHandlerInfo = new RoutedEventHandlerInfo(handler, handledEventsToo); // Get the entry corresponding to the given RoutedEvent FrugalObjectList<RoutedEventHandlerInfo> handlers = (FrugalObjectList<RoutedEventHandlerInfo>)this[routedEvent]; if (handlers == null) { _entries[routedEvent.GlobalIndex] = handlers = new FrugalObjectList<RoutedEventHandlerInfo>(1); } // Add the RoutedEventHandlerInfo to the list handlers.Add(routedEventHandlerInfo); } /// <summary> /// Removes an instance of the specified /// routed event handler for the given /// RoutedEvent from the store /// </summary> /// <remarks> /// NOTE: This method does nothing if no /// matching handler instances are found /// in the store /// </remarks> public void RemoveRoutedEventHandler(RoutedEvent routedEvent, Delegate handler) { ArgumentNullException.ThrowIfNull(routedEvent); ArgumentNullException.ThrowIfNull(handler); if (!routedEvent.IsLegalHandler(handler)) { throw new ArgumentException(SR.HandlerTypeIllegal); } // Get the entry corresponding to the given RoutedEvent FrugalObjectList<RoutedEventHandlerInfo> handlers = (FrugalObjectList<RoutedEventHandlerInfo>)this[routedEvent]; if (handlers != null && handlers.Count > 0) { if ((handlers.Count == 1) && (handlers[0].Handler == handler)) { // this is the only handler for this event and it's being removed // reclaim space in underlying FrugalMap by setting value to // DependencyProperty.UnsetValue _entries[routedEvent.GlobalIndex] = DependencyProperty.UnsetValue; } else { // When a matching instance is found remove it for (int i = 0; i < handlers.Count; i++) { if (handlers[i].Handler == handler) { handlers.RemoveAt(i); break; } } } } } /// <summary> /// Determines whether the given /// RoutedEvent exists in the store. /// </summary> /// <param name="routedEvent"> /// the RoutedEvent of the event. /// </param> public bool Contains(RoutedEvent routedEvent) { ArgumentNullException.ThrowIfNull(routedEvent); FrugalObjectList<RoutedEventHandlerInfo> handlers = (FrugalObjectList<RoutedEventHandlerInfo>)this[routedEvent]; return handlers != null && handlers.Count != 0; } /// <summary> /// Get all the event handlers in this store for the given routed event /// </summary> public RoutedEventHandlerInfo[] GetRoutedEventHandlers(RoutedEvent routedEvent) { ArgumentNullException.ThrowIfNull(routedEvent); FrugalObjectList<RoutedEventHandlerInfo> handlers = this[routedEvent]; if (handlers != null) { return handlers.ToArray(); } return null; } // Returns Handlers for the given key internal FrugalObjectList<RoutedEventHandlerInfo> this[RoutedEvent key] { get { Debug.Assert(key != null, "Search key cannot be null"); object list = _entries[key.GlobalIndex]; if (list == DependencyProperty.UnsetValue) { return null; } else { return (FrugalObjectList<RoutedEventHandlerInfo>)list; } } } internal Delegate this[EventPrivateKey key] { get { Debug.Assert(key != null, "Search key cannot be null"); object existingDelegate = _entries[key.GlobalIndex]; if (existingDelegate == DependencyProperty.UnsetValue) { return null; } else { return (Delegate)existingDelegate; } } } internal int Count { get { return _entries.Count; } } #endregion Operations #region Data // Map of EventPrivateKey/RoutedEvent to Delegate/FrugalObjectList<RoutedEventHandlerInfo> (respectively) private FrugalMap _entries; #endregion Data } }