1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 namespace System.ComponentModel
6 {
7     /// <summary>
8     ///    <para>Provides a simple list of delegates. This class cannot be inherited.</para>
9     /// </summary>
10     public sealed class EventHandlerList : IDisposable
11     {
12         private ListEntry _head;
13         private Component _parent;
14 
15         /// <summary>
16         ///     Creates a new event handler list.  The parent component is used to check the component's
17         ///     CanRaiseEvents property.
18         /// </summary>
19         internal EventHandlerList(Component parent) => _parent = parent;
20 
21         /// <summary>
22         ///    Creates a new event handler list.
23         /// </summary>
EventHandlerList()24         public EventHandlerList()
25         {
26         }
27 
28         /// <summary>
29         ///    <para>Gets or sets the delegate for the specified key.</para>
30         /// </summary>
31         public Delegate this[object key]
32         {
33             get
34             {
35                 ListEntry e = null;
36                 if (_parent == null || _parent.CanRaiseEventsInternal)
37                 {
38                     e = Find(key);
39                 }
40 
41                 return e?._handler;
42             }
43             set
44             {
45                 ListEntry e = Find(key);
46                 if (e != null)
47                 {
48                     e._handler = value;
49                 }
50                 else
51                 {
52                     _head = new ListEntry(key, value, _head);
53                 }
54             }
55         }
56 
57         /// <summary>
58         ///    <para>[To be supplied.]</para>
59         /// </summary>
AddHandler(object key, Delegate value)60         public void AddHandler(object key, Delegate value)
61         {
62             ListEntry e = Find(key);
63             if (e != null)
64             {
65                 e._handler = Delegate.Combine(e._handler, value);
66             }
67             else
68             {
69                 _head = new ListEntry(key, value, _head);
70             }
71         }
72 
73         /// <summary> allows you to add a list of events to this list </summary>
AddHandlers(EventHandlerList listToAddFrom)74         public void AddHandlers(EventHandlerList listToAddFrom)
75         {
76             ListEntry currentListEntry = listToAddFrom._head;
77             while (currentListEntry != null)
78             {
79                 AddHandler(currentListEntry._key, currentListEntry._handler);
80                 currentListEntry = currentListEntry._next;
81             }
82         }
83 
Dispose()84         public void Dispose() => _head = null;
85 
Find(object key)86         private ListEntry Find(object key)
87         {
88             ListEntry found = _head;
89             while (found != null)
90             {
91                 if (found._key == key)
92                 {
93                     break;
94                 }
95                 found = found._next;
96             }
97             return found;
98         }
99 
RemoveHandler(object key, Delegate value)100         public void RemoveHandler(object key, Delegate value)
101         {
102             ListEntry e = Find(key);
103             if (e != null)
104             {
105                 e._handler = Delegate.Remove(e._handler, value);
106             }
107             // else... no error for removal of non-existent delegate
108             //
109         }
110 
111         private sealed class ListEntry
112         {
113             internal ListEntry _next;
114             internal object _key;
115             internal Delegate _handler;
116 
ListEntry(object key, Delegate handler, ListEntry next)117             public ListEntry(object key, Delegate handler, ListEntry next)
118             {
119                 _next = next;
120                 _key = key;
121                 _handler = handler;
122             }
123         }
124     }
125 }
126