C#idiomatic C#
how-to-raise-and-consume-eventsstandard/events

Core library

Raise and consume events

Raise and consume events in .NET. See examples that use the EventHandler delegate, the EventHandler<TEventArgs> delegate, and a custom delegate.

  • page standard/events/how-to-raise-and-consume-events
  • updated 03/24/2026

This article shows how to work with events in .NET using the System.EventHandler delegate, the System.EventHandler delegate, and a custom delegate, with examples for events with and without data.

Prerequisites

Familiarize yourself with the concepts in the Events article.

Raise an event without data

These steps create a Counter class that fires a ThresholdReached event when a running total reaches or exceeds a threshold.

  1. Declare the event using the System.EventHandler delegate.

    Use EventHandler when your event doesn't pass data to the handler:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventNoData.csDeclareEvent

csharp
// <ThresholdReachedNoData>
class EventNoData
{
    static void Main()
    {
        Counter c = new(new Random().Next(10));
        // <SubscribeEvent>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent>
    static void c_ThresholdReached(object? sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
        Environment.Exit(0);
    }
    // </HandleEvent>
}

class Counter(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent>
        if (_total >= _threshold)
        {
            OnThresholdReached(EventArgs.Empty);
        }
        // </RaiseEvent>
    }

    // <RaiseEventMethod>
    protected virtual void OnThresholdReached(EventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod>

    // <DeclareEvent>
    public event EventHandler? ThresholdReached;
    // </DeclareEvent>
}
// </ThresholdReachedNoData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventNoData.vbDeclareEvent

vb
' <ThresholdReachedNoData>
Module EventNoData

    Sub Main()
        Dim c As New Counter(New Random().Next(10))
        ' <SubscribeEvent>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent>
    Sub c_ThresholdReached(sender As Object, e As EventArgs)
        Console.WriteLine("The threshold was reached.")
        Environment.Exit(0)
    End Sub
    ' </HandleEvent>
End Module

Class Counter
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent>
        If (_total >= _threshold) Then
            OnThresholdReached(EventArgs.Empty)
        End If
        ' </RaiseEvent>
    End Sub

    ' <RaiseEventMethod>
    Protected Overridable Sub OnThresholdReached(e As EventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod>

    ' <DeclareEvent>
    Public Event ThresholdReached As EventHandler
    ' </DeclareEvent>
End Class
' </ThresholdReachedNoData>

  1. Add a protected virtual method (Protected Overridable in Visual Basic) to raise the event.

    This pattern lets derived classes override the event-raising behavior without directly invoking the delegate. In C#, use the null-conditional operator (?.) to guard against no subscribers (in Visual Basic, RaiseEvent handles this automatically):

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventNoData.csRaiseEventMethod

csharp
// <ThresholdReachedNoData>
class EventNoData
{
    static void Main()
    {
        Counter c = new(new Random().Next(10));
        // <SubscribeEvent>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent>
    static void c_ThresholdReached(object? sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
        Environment.Exit(0);
    }
    // </HandleEvent>
}

class Counter(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent>
        if (_total >= _threshold)
        {
            OnThresholdReached(EventArgs.Empty);
        }
        // </RaiseEvent>
    }

    // <RaiseEventMethod>
    protected virtual void OnThresholdReached(EventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod>

    // <DeclareEvent>
    public event EventHandler? ThresholdReached;
    // </DeclareEvent>
}
// </ThresholdReachedNoData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventNoData.vbRaiseEventMethod

vb
' <ThresholdReachedNoData>
Module EventNoData

    Sub Main()
        Dim c As New Counter(New Random().Next(10))
        ' <SubscribeEvent>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent>
    Sub c_ThresholdReached(sender As Object, e As EventArgs)
        Console.WriteLine("The threshold was reached.")
        Environment.Exit(0)
    End Sub
    ' </HandleEvent>
End Module

Class Counter
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent>
        If (_total >= _threshold) Then
            OnThresholdReached(EventArgs.Empty)
        End If
        ' </RaiseEvent>
    End Sub

    ' <RaiseEventMethod>
    Protected Overridable Sub OnThresholdReached(e As EventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod>

    ' <DeclareEvent>
    Public Event ThresholdReached As EventHandler
    ' </DeclareEvent>
End Class
' </ThresholdReachedNoData>

  1. Call the raise method when the condition is met.

    Pass System.EventArgs.Empty because this event carries no data:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventNoData.csRaiseEvent

csharp
// <ThresholdReachedNoData>
class EventNoData
{
    static void Main()
    {
        Counter c = new(new Random().Next(10));
        // <SubscribeEvent>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent>
    static void c_ThresholdReached(object? sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
        Environment.Exit(0);
    }
    // </HandleEvent>
}

class Counter(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent>
        if (_total >= _threshold)
        {
            OnThresholdReached(EventArgs.Empty);
        }
        // </RaiseEvent>
    }

    // <RaiseEventMethod>
    protected virtual void OnThresholdReached(EventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod>

    // <DeclareEvent>
    public event EventHandler? ThresholdReached;
    // </DeclareEvent>
}
// </ThresholdReachedNoData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventNoData.vbRaiseEvent

vb
' <ThresholdReachedNoData>
Module EventNoData

    Sub Main()
        Dim c As New Counter(New Random().Next(10))
        ' <SubscribeEvent>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent>
    Sub c_ThresholdReached(sender As Object, e As EventArgs)
        Console.WriteLine("The threshold was reached.")
        Environment.Exit(0)
    End Sub
    ' </HandleEvent>
End Module

Class Counter
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent>
        If (_total >= _threshold) Then
            OnThresholdReached(EventArgs.Empty)
        End If
        ' </RaiseEvent>
    End Sub

    ' <RaiseEventMethod>
    Protected Overridable Sub OnThresholdReached(e As EventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod>

    ' <DeclareEvent>
    Public Event ThresholdReached As EventHandler
    ' </DeclareEvent>
End Class
' </ThresholdReachedNoData>

  1. Subscribe to the event using the += operator (in Visual Basic, AddHandler):

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventNoData.csSubscribeEvent

csharp
// <ThresholdReachedNoData>
class EventNoData
{
    static void Main()
    {
        Counter c = new(new Random().Next(10));
        // <SubscribeEvent>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent>
    static void c_ThresholdReached(object? sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
        Environment.Exit(0);
    }
    // </HandleEvent>
}

class Counter(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent>
        if (_total >= _threshold)
        {
            OnThresholdReached(EventArgs.Empty);
        }
        // </RaiseEvent>
    }

    // <RaiseEventMethod>
    protected virtual void OnThresholdReached(EventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod>

    // <DeclareEvent>
    public event EventHandler? ThresholdReached;
    // </DeclareEvent>
}
// </ThresholdReachedNoData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventNoData.vbSubscribeEvent

vb
' <ThresholdReachedNoData>
Module EventNoData

    Sub Main()
        Dim c As New Counter(New Random().Next(10))
        ' <SubscribeEvent>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent>
    Sub c_ThresholdReached(sender As Object, e As EventArgs)
        Console.WriteLine("The threshold was reached.")
        Environment.Exit(0)
    End Sub
    ' </HandleEvent>
End Module

Class Counter
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent>
        If (_total >= _threshold) Then
            OnThresholdReached(EventArgs.Empty)
        End If
        ' </RaiseEvent>
    End Sub

    ' <RaiseEventMethod>
    Protected Overridable Sub OnThresholdReached(e As EventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod>

    ' <DeclareEvent>
    Public Event ThresholdReached As EventHandler
    ' </DeclareEvent>
End Class
' </ThresholdReachedNoData>

  1. Define the event handler method.

    Its signature must match the System.EventHandler delegate—the first parameter is the event source and the second is System.EventArgs:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventNoData.csHandleEvent

csharp
// <ThresholdReachedNoData>
class EventNoData
{
    static void Main()
    {
        Counter c = new(new Random().Next(10));
        // <SubscribeEvent>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent>
    static void c_ThresholdReached(object? sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
        Environment.Exit(0);
    }
    // </HandleEvent>
}

class Counter(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent>
        if (_total >= _threshold)
        {
            OnThresholdReached(EventArgs.Empty);
        }
        // </RaiseEvent>
    }

    // <RaiseEventMethod>
    protected virtual void OnThresholdReached(EventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod>

    // <DeclareEvent>
    public event EventHandler? ThresholdReached;
    // </DeclareEvent>
}
// </ThresholdReachedNoData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventNoData.vbHandleEvent

vb
' <ThresholdReachedNoData>
Module EventNoData

    Sub Main()
        Dim c As New Counter(New Random().Next(10))
        ' <SubscribeEvent>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent>
    Sub c_ThresholdReached(sender As Object, e As EventArgs)
        Console.WriteLine("The threshold was reached.")
        Environment.Exit(0)
    End Sub
    ' </HandleEvent>
End Module

Class Counter
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent>
        If (_total >= _threshold) Then
            OnThresholdReached(EventArgs.Empty)
        End If
        ' </RaiseEvent>
    End Sub

    ' <RaiseEventMethod>
    Protected Overridable Sub OnThresholdReached(e As EventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod>

    ' <DeclareEvent>
    Public Event ThresholdReached As EventHandler
    ' </DeclareEvent>
End Class
' </ThresholdReachedNoData>

The following example shows the complete implementation:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventNoData.csThresholdReachedNoData

csharp
// <ThresholdReachedNoData>
class EventNoData
{
    static void Main()
    {
        Counter c = new(new Random().Next(10));
        // <SubscribeEvent>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent>
    static void c_ThresholdReached(object? sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
        Environment.Exit(0);
    }
    // </HandleEvent>
}

class Counter(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent>
        if (_total >= _threshold)
        {
            OnThresholdReached(EventArgs.Empty);
        }
        // </RaiseEvent>
    }

    // <RaiseEventMethod>
    protected virtual void OnThresholdReached(EventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod>

    // <DeclareEvent>
    public event EventHandler? ThresholdReached;
    // </DeclareEvent>
}
// </ThresholdReachedNoData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventNoData.vbThresholdReachedNoData

vb
' <ThresholdReachedNoData>
Module EventNoData

    Sub Main()
        Dim c As New Counter(New Random().Next(10))
        ' <SubscribeEvent>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent>
    Sub c_ThresholdReached(sender As Object, e As EventArgs)
        Console.WriteLine("The threshold was reached.")
        Environment.Exit(0)
    End Sub
    ' </HandleEvent>
End Module

Class Counter
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent>
        If (_total >= _threshold) Then
            OnThresholdReached(EventArgs.Empty)
        End If
        ' </RaiseEvent>
    End Sub

    ' <RaiseEventMethod>
    Protected Overridable Sub OnThresholdReached(e As EventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod>

    ' <DeclareEvent>
    Public Event ThresholdReached As EventHandler
    ' </DeclareEvent>
End Class
' </ThresholdReachedNoData>

Raise an event with data

These steps extend the previous Counter example to raise an event that includes data—the threshold value and the time it was reached.

  1. Define an event data class that inherits from System.EventArgs.

    Add properties for each piece of data you want to pass to the handler:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithData.csEventDataClass2

csharp
// <ThresholdReachedWithData>
class EventWithData
{
    static void Main()
    {
        CounterWithData c = new(new Random().Next(10));
        // <SubscribeEvent2>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent2>
    static void c_ThresholdReached(object? sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEvent2>
}

class CounterWithData(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent2>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEvent2>
    }

    // <RaiseEventMethod2>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod2>

    // <DeclareEvent2>
    public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
    // </DeclareEvent2>
}

// <EventDataClass2>
public class ThresholdReachedEventArgs : EventArgs
{
    public int Threshold { get; set; }
    public DateTime TimeReached { get; set; }
}
// </EventDataClass2>
// </ThresholdReachedWithData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithData.vbEventDataClass2

vb
' <ThresholdReachedWithData>
Module EventWithData

    Sub Main()
        Dim c As New CounterWithData(New Random().Next(10))
        ' <SubscribeEvent2>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent2>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEvent2>
End Module

Class CounterWithData
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent2>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEvent2>
    End Sub

    ' <RaiseEventMethod2>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod2>

    ' <DeclareEvent2>
    Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
    ' </DeclareEvent2>
End Class

' <EventDataClass2>
Class ThresholdReachedEventArgs
    Inherits EventArgs

    Public Property Threshold As Integer
    Public Property TimeReached As Date
End Class
' </EventDataClass2>
' </ThresholdReachedWithData>

  1. Declare the event using the System.EventHandler delegate, passing your event data class as the type argument:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithData.csDeclareEvent2

csharp
// <ThresholdReachedWithData>
class EventWithData
{
    static void Main()
    {
        CounterWithData c = new(new Random().Next(10));
        // <SubscribeEvent2>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent2>
    static void c_ThresholdReached(object? sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEvent2>
}

class CounterWithData(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent2>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEvent2>
    }

    // <RaiseEventMethod2>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod2>

    // <DeclareEvent2>
    public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
    // </DeclareEvent2>
}

// <EventDataClass2>
public class ThresholdReachedEventArgs : EventArgs
{
    public int Threshold { get; set; }
    public DateTime TimeReached { get; set; }
}
// </EventDataClass2>
// </ThresholdReachedWithData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithData.vbDeclareEvent2

vb
' <ThresholdReachedWithData>
Module EventWithData

    Sub Main()
        Dim c As New CounterWithData(New Random().Next(10))
        ' <SubscribeEvent2>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent2>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEvent2>
End Module

Class CounterWithData
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent2>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEvent2>
    End Sub

    ' <RaiseEventMethod2>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod2>

    ' <DeclareEvent2>
    Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
    ' </DeclareEvent2>
End Class

' <EventDataClass2>
Class ThresholdReachedEventArgs
    Inherits EventArgs

    Public Property Threshold As Integer
    Public Property TimeReached As Date
End Class
' </EventDataClass2>
' </ThresholdReachedWithData>

  1. Add a protected virtual method (Protected Overridable in Visual Basic) to raise the event.

    This pattern lets derived classes override the event-raising behavior without directly invoking the delegate. In C#, use the null-conditional operator (?.) to guard against no subscribers (in Visual Basic, RaiseEvent handles this automatically):

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithData.csRaiseEventMethod2

csharp
// <ThresholdReachedWithData>
class EventWithData
{
    static void Main()
    {
        CounterWithData c = new(new Random().Next(10));
        // <SubscribeEvent2>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent2>
    static void c_ThresholdReached(object? sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEvent2>
}

class CounterWithData(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent2>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEvent2>
    }

    // <RaiseEventMethod2>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod2>

    // <DeclareEvent2>
    public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
    // </DeclareEvent2>
}

// <EventDataClass2>
public class ThresholdReachedEventArgs : EventArgs
{
    public int Threshold { get; set; }
    public DateTime TimeReached { get; set; }
}
// </EventDataClass2>
// </ThresholdReachedWithData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithData.vbRaiseEventMethod2

vb
' <ThresholdReachedWithData>
Module EventWithData

    Sub Main()
        Dim c As New CounterWithData(New Random().Next(10))
        ' <SubscribeEvent2>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent2>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEvent2>
End Module

Class CounterWithData
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent2>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEvent2>
    End Sub

    ' <RaiseEventMethod2>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod2>

    ' <DeclareEvent2>
    Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
    ' </DeclareEvent2>
End Class

' <EventDataClass2>
Class ThresholdReachedEventArgs
    Inherits EventArgs

    Public Property Threshold As Integer
    Public Property TimeReached As Date
End Class
' </EventDataClass2>
' </ThresholdReachedWithData>

  1. Populate the event data object and call the raise method when the condition is met:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithData.csRaiseEvent2

csharp
// <ThresholdReachedWithData>
class EventWithData
{
    static void Main()
    {
        CounterWithData c = new(new Random().Next(10));
        // <SubscribeEvent2>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent2>
    static void c_ThresholdReached(object? sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEvent2>
}

class CounterWithData(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent2>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEvent2>
    }

    // <RaiseEventMethod2>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod2>

    // <DeclareEvent2>
    public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
    // </DeclareEvent2>
}

// <EventDataClass2>
public class ThresholdReachedEventArgs : EventArgs
{
    public int Threshold { get; set; }
    public DateTime TimeReached { get; set; }
}
// </EventDataClass2>
// </ThresholdReachedWithData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithData.vbRaiseEvent2

vb
' <ThresholdReachedWithData>
Module EventWithData

    Sub Main()
        Dim c As New CounterWithData(New Random().Next(10))
        ' <SubscribeEvent2>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent2>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEvent2>
End Module

Class CounterWithData
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent2>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEvent2>
    End Sub

    ' <RaiseEventMethod2>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod2>

    ' <DeclareEvent2>
    Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
    ' </DeclareEvent2>
End Class

' <EventDataClass2>
Class ThresholdReachedEventArgs
    Inherits EventArgs

    Public Property Threshold As Integer
    Public Property TimeReached As Date
End Class
' </EventDataClass2>
' </ThresholdReachedWithData>

  1. Subscribe to the event using the += operator (in Visual Basic, AddHandler):

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithData.csSubscribeEvent2

csharp
// <ThresholdReachedWithData>
class EventWithData
{
    static void Main()
    {
        CounterWithData c = new(new Random().Next(10));
        // <SubscribeEvent2>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent2>
    static void c_ThresholdReached(object? sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEvent2>
}

class CounterWithData(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent2>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEvent2>
    }

    // <RaiseEventMethod2>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod2>

    // <DeclareEvent2>
    public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
    // </DeclareEvent2>
}

// <EventDataClass2>
public class ThresholdReachedEventArgs : EventArgs
{
    public int Threshold { get; set; }
    public DateTime TimeReached { get; set; }
}
// </EventDataClass2>
// </ThresholdReachedWithData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithData.vbSubscribeEvent2

vb
' <ThresholdReachedWithData>
Module EventWithData

    Sub Main()
        Dim c As New CounterWithData(New Random().Next(10))
        ' <SubscribeEvent2>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent2>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEvent2>
End Module

Class CounterWithData
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent2>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEvent2>
    End Sub

    ' <RaiseEventMethod2>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod2>

    ' <DeclareEvent2>
    Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
    ' </DeclareEvent2>
End Class

' <EventDataClass2>
Class ThresholdReachedEventArgs
    Inherits EventArgs

    Public Property Threshold As Integer
    Public Property TimeReached As Date
End Class
' </EventDataClass2>
' </ThresholdReachedWithData>

  1. Define the event handler.

    The second parameter type is ThresholdReachedEventArgs instead of System.EventArgs, which lets the handler read the event data:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithData.csHandleEvent2

csharp
// <ThresholdReachedWithData>
class EventWithData
{
    static void Main()
    {
        CounterWithData c = new(new Random().Next(10));
        // <SubscribeEvent2>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent2>
    static void c_ThresholdReached(object? sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEvent2>
}

class CounterWithData(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent2>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEvent2>
    }

    // <RaiseEventMethod2>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod2>

    // <DeclareEvent2>
    public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
    // </DeclareEvent2>
}

// <EventDataClass2>
public class ThresholdReachedEventArgs : EventArgs
{
    public int Threshold { get; set; }
    public DateTime TimeReached { get; set; }
}
// </EventDataClass2>
// </ThresholdReachedWithData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithData.vbHandleEvent2

vb
' <ThresholdReachedWithData>
Module EventWithData

    Sub Main()
        Dim c As New CounterWithData(New Random().Next(10))
        ' <SubscribeEvent2>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent2>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEvent2>
End Module

Class CounterWithData
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent2>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEvent2>
    End Sub

    ' <RaiseEventMethod2>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod2>

    ' <DeclareEvent2>
    Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
    ' </DeclareEvent2>
End Class

' <EventDataClass2>
Class ThresholdReachedEventArgs
    Inherits EventArgs

    Public Property Threshold As Integer
    Public Property TimeReached As Date
End Class
' </EventDataClass2>
' </ThresholdReachedWithData>

The following example shows the complete implementation:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithData.csThresholdReachedWithData

csharp
// <ThresholdReachedWithData>
class EventWithData
{
    static void Main()
    {
        CounterWithData c = new(new Random().Next(10));
        // <SubscribeEvent2>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEvent2>
    static void c_ThresholdReached(object? sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEvent2>
}

class CounterWithData(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEvent2>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEvent2>
    }

    // <RaiseEventMethod2>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethod2>

    // <DeclareEvent2>
    public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
    // </DeclareEvent2>
}

// <EventDataClass2>
public class ThresholdReachedEventArgs : EventArgs
{
    public int Threshold { get; set; }
    public DateTime TimeReached { get; set; }
}
// </EventDataClass2>
// </ThresholdReachedWithData>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithData.vbThresholdReachedWithData

vb
' <ThresholdReachedWithData>
Module EventWithData

    Sub Main()
        Dim c As New CounterWithData(New Random().Next(10))
        ' <SubscribeEvent2>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEvent2>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEvent2>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEvent2>
End Module

Class CounterWithData
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEvent2>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEvent2>
    End Sub

    ' <RaiseEventMethod2>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethod2>

    ' <DeclareEvent2>
    Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
    ' </DeclareEvent2>
End Class

' <EventDataClass2>
Class ThresholdReachedEventArgs
    Inherits EventArgs

    Public Property Threshold As Integer
    Public Property TimeReached As Date
End Class
' </EventDataClass2>
' </ThresholdReachedWithData>

Declare a custom delegate for an event

Declare a custom delegate only in rare scenarios, such as making your class available to legacy code that can't use generics. For most cases, use System.EventHandler as shown in the previous section.

  1. Declare the custom delegate type.

    The delegate signature must match the event handler signature—two parameters: the event source (object; in Visual Basic, Object) and the event data class:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithDelegate.csDeclareDelegateType

csharp
// <ThresholdReachedWithDelegate>
class EventWithDelegate
{
    static void Main()
    {
        CounterWithDelegate c = new(new Random().Next(10));
        // <SubscribeEventDelegate>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEventDelegate>
    static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEventDelegate>
}

class CounterWithDelegate(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEventDelegate>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEventDelegate>
    }

    // <RaiseEventMethodDelegate>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethodDelegate>

    // <DeclareEventWithDelegate>
    public event ThresholdReachedEventHandler? ThresholdReached;
    // </DeclareEventWithDelegate>
}

// <DeclareDelegateType>
public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
// </DeclareDelegateType>
// </ThresholdReachedWithDelegate>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithDelegate.vbDeclareDelegateType

vb
' <ThresholdReachedWithDelegate>
Module EventWithDelegate

    Sub Main()
        Dim c As New CounterWithDelegate(New Random().Next(10))
        ' <SubscribeEventDelegate>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEventDelegate>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEventDelegate>
End Module

Class CounterWithDelegate
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEventDelegate>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEventDelegate>
    End Sub

    ' <RaiseEventMethodDelegate>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethodDelegate>

    ' <DeclareEventWithDelegate>
    Public Event ThresholdReached As ThresholdReachedEventHandler
    ' </DeclareEventWithDelegate>
End Class

' <DeclareDelegateType>
Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)
' </DeclareDelegateType>
' </ThresholdReachedWithDelegate>

  1. Declare the event using your custom delegate type instead of System.EventHandler:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithDelegate.csDeclareEventWithDelegate

csharp
// <ThresholdReachedWithDelegate>
class EventWithDelegate
{
    static void Main()
    {
        CounterWithDelegate c = new(new Random().Next(10));
        // <SubscribeEventDelegate>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEventDelegate>
    static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEventDelegate>
}

class CounterWithDelegate(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEventDelegate>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEventDelegate>
    }

    // <RaiseEventMethodDelegate>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethodDelegate>

    // <DeclareEventWithDelegate>
    public event ThresholdReachedEventHandler? ThresholdReached;
    // </DeclareEventWithDelegate>
}

// <DeclareDelegateType>
public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
// </DeclareDelegateType>
// </ThresholdReachedWithDelegate>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithDelegate.vbDeclareEventWithDelegate

vb
' <ThresholdReachedWithDelegate>
Module EventWithDelegate

    Sub Main()
        Dim c As New CounterWithDelegate(New Random().Next(10))
        ' <SubscribeEventDelegate>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEventDelegate>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEventDelegate>
End Module

Class CounterWithDelegate
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEventDelegate>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEventDelegate>
    End Sub

    ' <RaiseEventMethodDelegate>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethodDelegate>

    ' <DeclareEventWithDelegate>
    Public Event ThresholdReached As ThresholdReachedEventHandler
    ' </DeclareEventWithDelegate>
End Class

' <DeclareDelegateType>
Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)
' </DeclareDelegateType>
' </ThresholdReachedWithDelegate>

  1. Add a protected virtual method (Protected Overridable in Visual Basic) to raise the event.

    In C#, use the null-conditional operator (?.) to guard against no subscribers (in Visual Basic, RaiseEvent handles this automatically):

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithDelegate.csRaiseEventMethodDelegate

csharp
// <ThresholdReachedWithDelegate>
class EventWithDelegate
{
    static void Main()
    {
        CounterWithDelegate c = new(new Random().Next(10));
        // <SubscribeEventDelegate>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEventDelegate>
    static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEventDelegate>
}

class CounterWithDelegate(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEventDelegate>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEventDelegate>
    }

    // <RaiseEventMethodDelegate>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethodDelegate>

    // <DeclareEventWithDelegate>
    public event ThresholdReachedEventHandler? ThresholdReached;
    // </DeclareEventWithDelegate>
}

// <DeclareDelegateType>
public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
// </DeclareDelegateType>
// </ThresholdReachedWithDelegate>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithDelegate.vbRaiseEventMethodDelegate

vb
' <ThresholdReachedWithDelegate>
Module EventWithDelegate

    Sub Main()
        Dim c As New CounterWithDelegate(New Random().Next(10))
        ' <SubscribeEventDelegate>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEventDelegate>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEventDelegate>
End Module

Class CounterWithDelegate
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEventDelegate>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEventDelegate>
    End Sub

    ' <RaiseEventMethodDelegate>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethodDelegate>

    ' <DeclareEventWithDelegate>
    Public Event ThresholdReached As ThresholdReachedEventHandler
    ' </DeclareEventWithDelegate>
End Class

' <DeclareDelegateType>
Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)
' </DeclareDelegateType>
' </ThresholdReachedWithDelegate>

  1. Populate the event data object and call the raise method when the condition is met:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithDelegate.csRaiseEventDelegate

csharp
// <ThresholdReachedWithDelegate>
class EventWithDelegate
{
    static void Main()
    {
        CounterWithDelegate c = new(new Random().Next(10));
        // <SubscribeEventDelegate>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEventDelegate>
    static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEventDelegate>
}

class CounterWithDelegate(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEventDelegate>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEventDelegate>
    }

    // <RaiseEventMethodDelegate>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethodDelegate>

    // <DeclareEventWithDelegate>
    public event ThresholdReachedEventHandler? ThresholdReached;
    // </DeclareEventWithDelegate>
}

// <DeclareDelegateType>
public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
// </DeclareDelegateType>
// </ThresholdReachedWithDelegate>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithDelegate.vbRaiseEventDelegate

vb
' <ThresholdReachedWithDelegate>
Module EventWithDelegate

    Sub Main()
        Dim c As New CounterWithDelegate(New Random().Next(10))
        ' <SubscribeEventDelegate>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEventDelegate>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEventDelegate>
End Module

Class CounterWithDelegate
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEventDelegate>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEventDelegate>
    End Sub

    ' <RaiseEventMethodDelegate>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethodDelegate>

    ' <DeclareEventWithDelegate>
    Public Event ThresholdReached As ThresholdReachedEventHandler
    ' </DeclareEventWithDelegate>
End Class

' <DeclareDelegateType>
Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)
' </DeclareDelegateType>
' </ThresholdReachedWithDelegate>

  1. Subscribe to the event using the += operator (in Visual Basic, AddHandler):

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithDelegate.csSubscribeEventDelegate

csharp
// <ThresholdReachedWithDelegate>
class EventWithDelegate
{
    static void Main()
    {
        CounterWithDelegate c = new(new Random().Next(10));
        // <SubscribeEventDelegate>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEventDelegate>
    static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEventDelegate>
}

class CounterWithDelegate(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEventDelegate>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEventDelegate>
    }

    // <RaiseEventMethodDelegate>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethodDelegate>

    // <DeclareEventWithDelegate>
    public event ThresholdReachedEventHandler? ThresholdReached;
    // </DeclareEventWithDelegate>
}

// <DeclareDelegateType>
public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
// </DeclareDelegateType>
// </ThresholdReachedWithDelegate>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithDelegate.vbSubscribeEventDelegate

vb
' <ThresholdReachedWithDelegate>
Module EventWithDelegate

    Sub Main()
        Dim c As New CounterWithDelegate(New Random().Next(10))
        ' <SubscribeEventDelegate>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEventDelegate>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEventDelegate>
End Module

Class CounterWithDelegate
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEventDelegate>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEventDelegate>
    End Sub

    ' <RaiseEventMethodDelegate>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethodDelegate>

    ' <DeclareEventWithDelegate>
    Public Event ThresholdReached As ThresholdReachedEventHandler
    ' </DeclareEventWithDelegate>
End Class

' <DeclareDelegateType>
Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)
' </DeclareDelegateType>
' </ThresholdReachedWithDelegate>

  1. Define the event handler.

    The handler signature must match the custom delegate—object for the sender and your event data class for the second parameter:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithDelegate.csHandleEventDelegate

csharp
// <ThresholdReachedWithDelegate>
class EventWithDelegate
{
    static void Main()
    {
        CounterWithDelegate c = new(new Random().Next(10));
        // <SubscribeEventDelegate>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEventDelegate>
    static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEventDelegate>
}

class CounterWithDelegate(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEventDelegate>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEventDelegate>
    }

    // <RaiseEventMethodDelegate>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethodDelegate>

    // <DeclareEventWithDelegate>
    public event ThresholdReachedEventHandler? ThresholdReached;
    // </DeclareEventWithDelegate>
}

// <DeclareDelegateType>
public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
// </DeclareDelegateType>
// </ThresholdReachedWithDelegate>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithDelegate.vbHandleEventDelegate

vb
' <ThresholdReachedWithDelegate>
Module EventWithDelegate

    Sub Main()
        Dim c As New CounterWithDelegate(New Random().Next(10))
        ' <SubscribeEventDelegate>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEventDelegate>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEventDelegate>
End Module

Class CounterWithDelegate
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEventDelegate>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEventDelegate>
    End Sub

    ' <RaiseEventMethodDelegate>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethodDelegate>

    ' <DeclareEventWithDelegate>
    Public Event ThresholdReached As ThresholdReachedEventHandler
    ' </DeclareEventWithDelegate>
End Class

' <DeclareDelegateType>
Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)
' </DeclareDelegateType>
' </ThresholdReachedWithDelegate>

The following example shows the complete implementation:

sample · csharpdocs/standard/events/snippets/how-to-raise-and-consume-events/csharp/EventWithDelegate.csThresholdReachedWithDelegate

csharp
// <ThresholdReachedWithDelegate>
class EventWithDelegate
{
    static void Main()
    {
        CounterWithDelegate c = new(new Random().Next(10));
        // <SubscribeEventDelegate>
        c.ThresholdReached += c_ThresholdReached;
        // </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        {
            Console.WriteLine("adding one");
            c.Add(1);
        }
    }

    // <HandleEventDelegate>
    static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    {
        Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
        Environment.Exit(0);
    }
    // </HandleEventDelegate>
}

class CounterWithDelegate(int passedThreshold)
{
    private readonly int _threshold = passedThreshold;
    private int _total;

    public void Add(int x)
    {
        _total += x;
        // <RaiseEventDelegate>
        if (_total >= _threshold)
        {
            ThresholdReachedEventArgs args = new();
            args.Threshold = _threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        }
        // </RaiseEventDelegate>
    }

    // <RaiseEventMethodDelegate>
    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
        ThresholdReached?.Invoke(this, e);
    }
    // </RaiseEventMethodDelegate>

    // <DeclareEventWithDelegate>
    public event ThresholdReachedEventHandler? ThresholdReached;
    // </DeclareEventWithDelegate>
}

// <DeclareDelegateType>
public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
// </DeclareDelegateType>
// </ThresholdReachedWithDelegate>

sample · vbdocs/standard/events/snippets/how-to-raise-and-consume-events/vb/EventWithDelegate.vbThresholdReachedWithDelegate

vb
' <ThresholdReachedWithDelegate>
Module EventWithDelegate

    Sub Main()
        Dim c As New CounterWithDelegate(New Random().Next(10))
        ' <SubscribeEventDelegate>
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
        ' </SubscribeEventDelegate>

        Console.WriteLine("press 'a' key to increase total")
        While Console.ReadKey(True).KeyChar = "a"
            Console.WriteLine("adding one")
            c.Add(1)
        End While
    End Sub

    ' <HandleEventDelegate>
    Sub c_ThresholdReached(sender As Object, e As ThresholdReachedEventArgs)
        Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold, e.TimeReached)
        Environment.Exit(0)
    End Sub
    ' </HandleEventDelegate>
End Module

Class CounterWithDelegate
    Private ReadOnly _threshold As Integer
    Private _total As Integer

    Public Sub New(passedThreshold As Integer)
        _threshold = passedThreshold
    End Sub

    Public Sub Add(x As Integer)
        _total += x
        ' <RaiseEventDelegate>
        If (_total >= _threshold) Then
            Dim args As New ThresholdReachedEventArgs With {
                .Threshold = _threshold,
                .TimeReached = Date.Now
            }
            OnThresholdReached(args)
        End If
        ' </RaiseEventDelegate>
    End Sub

    ' <RaiseEventMethodDelegate>
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub
    ' </RaiseEventMethodDelegate>

    ' <DeclareEventWithDelegate>
    Public Event ThresholdReached As ThresholdReachedEventHandler
    ' </DeclareEventWithDelegate>
End Class

' <DeclareDelegateType>
Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)
' </DeclareDelegateType>
' </ThresholdReachedWithDelegate>