|
| 1 | +--- |
| 2 | +title: "Declare multiple events using event properties" |
| 3 | +description: Learn how to declare many events by using event properties. Define delegate collections, event keys, and event properties. Implement add and remove accessor methods. |
| 4 | +ms.date: 03/25/2026 |
| 5 | +ms.topic: how-to |
| 6 | +dev_langs: |
| 7 | + - "csharp" |
| 8 | + - "vb" |
| 9 | +helpviewer_keywords: |
| 10 | + - "event properties [.NET]" |
| 11 | + - "multiple events [.NET]" |
| 12 | + - "event handling [.NET], with multiple events" |
| 13 | + - "events [.NET], multiple" |
| 14 | +ai-usage: ai-assisted |
| 15 | +--- |
| 16 | + |
| 17 | +# Declare multiple events using event properties |
| 18 | + |
| 19 | +When a class defines many events using field-like event declarations, the compiler generates a backing field for each one. Every instance of that class allocates memory for all of those fields—even for events that are never subscribed. With many events, this per-instance overhead wastes memory. |
| 20 | + |
| 21 | +To avoid this memory overhead, use event properties backed by a delegate collection. The collection must provide methods that set, access, and retrieve delegates by event key. <xref:System.ComponentModel.EventHandlerList> is designed for this purpose, but you can also use a <xref:System.Collections.Hashtable> or a class derived from <xref:System.Collections.DictionaryBase>. Keep the collection's implementation details private. |
| 22 | + |
| 23 | +Each event property defines an add accessor and a remove accessor. The add accessor adds the input delegate to the delegate collection, and the remove accessor removes it. Both accessors use a predefined key to add and remove instances from the collection. |
| 24 | + |
| 25 | +## Prerequisites |
| 26 | + |
| 27 | +Familiarize yourself with the concepts in the [Events](index.md) article. |
| 28 | + |
| 29 | +## Define multiple events using event properties |
| 30 | + |
| 31 | +These steps create a `Sensor` class that exposes 10 event properties, all backed by a single `EventHandlerList`. |
| 32 | + |
| 33 | +1. Define an event data class that inherits from <xref:System.EventArgs>. |
| 34 | + |
| 35 | + Add properties for each piece of data you want to pass to the handler: |
| 36 | + |
| 37 | + :::code language="csharp" source="./snippets/how-to-handle-multiple-events-using-event-properties/csharp/Sensor.cs" id="SensorEventArgs"::: |
| 38 | + :::code language="vb" source="./snippets/how-to-handle-multiple-events-using-event-properties/vb/Sensor.vb" id="SensorEventArgs"::: |
| 39 | + |
| 40 | +1. Declare an <xref:System.ComponentModel.EventHandlerList> field to store the delegates: |
| 41 | + |
| 42 | + :::code language="csharp" source="./snippets/how-to-handle-multiple-events-using-event-properties/csharp/Sensor.cs" id="EventHandlerListField"::: |
| 43 | + :::code language="vb" source="./snippets/how-to-handle-multiple-events-using-event-properties/vb/Sensor.vb" id="EventHandlerListField"::: |
| 44 | + |
| 45 | +1. Declare a unique key for each event. |
| 46 | + |
| 47 | + `EventHandlerList` stores delegates by key. Use a `static readonly` object (`Shared ReadOnly` in Visual Basic) for each key—object identity ensures each key is truly unique: |
| 48 | + |
| 49 | + :::code language="csharp" source="./snippets/how-to-handle-multiple-events-using-event-properties/csharp/Sensor.cs" id="EventKeys"::: |
| 50 | + :::code language="vb" source="./snippets/how-to-handle-multiple-events-using-event-properties/vb/Sensor.vb" id="EventKeys"::: |
| 51 | + |
| 52 | +1. Define each event as an event property with custom add and remove accessors. |
| 53 | + |
| 54 | + Each accessor calls `AddHandler` or `RemoveHandler` on the list using that event's key. In C#, also add a `protected virtual` raise method that retrieves the delegate from the list by key and invokes it. In Visual Basic, the `Custom Event` declaration already includes a `RaiseEvent` block that does this: |
| 55 | + |
| 56 | + :::code language="csharp" source="./snippets/how-to-handle-multiple-events-using-event-properties/csharp/Sensor.cs" id="SingleEventProperty"::: |
| 57 | + :::code language="vb" source="./snippets/how-to-handle-multiple-events-using-event-properties/vb/Sensor.vb" id="SingleEventProperty"::: |
| 58 | + |
| 59 | + Repeat this pattern for each event, using its corresponding key. |
| 60 | + |
| 61 | +1. Subscribe to the event using the `+=` operator (in Visual Basic, `AddHandler`): |
| 62 | + |
| 63 | + :::code language="csharp" source="./snippets/how-to-handle-multiple-events-using-event-properties/csharp/Program.cs" id="SubscribeEvent"::: |
| 64 | + :::code language="vb" source="./snippets/how-to-handle-multiple-events-using-event-properties/vb/Program.vb" id="SubscribeEvent"::: |
| 65 | + |
| 66 | +1. Define the event handler. |
| 67 | + |
| 68 | + The signature must match the <xref:System.EventHandler`1> delegate—an `object` sender and your event data class as the second parameter: |
| 69 | + |
| 70 | + :::code language="csharp" source="./snippets/how-to-handle-multiple-events-using-event-properties/csharp/Program.cs" id="HandleEvent"::: |
| 71 | + :::code language="vb" source="./snippets/how-to-handle-multiple-events-using-event-properties/vb/Program.vb" id="HandleEvent"::: |
| 72 | + |
| 73 | +The following example shows the complete `Sensor` class implementation: |
| 74 | + |
| 75 | +:::code language="csharp" source="./snippets/how-to-handle-multiple-events-using-event-properties/csharp/Sensor.cs" id="EventProperties"::: |
| 76 | +:::code language="vb" source="./snippets/how-to-handle-multiple-events-using-event-properties/vb/Sensor.vb" id="EventProperties"::: |
| 77 | + |
| 78 | +## Related content |
| 79 | + |
| 80 | +- <xref:System.ComponentModel.EventHandlerList?displayProperty=nameWithType> |
| 81 | +- [Events](index.md) |
0 commit comments