Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

Raise and consume events

This article shows how to work with events in .NET using the EventHandler delegate, the EventHandler<TEventArgs> 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 EventHandler delegate.

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

    public event EventHandler? ThresholdReached;
    
    Public Event ThresholdReached As EventHandler
    
  2. 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):

    protected virtual void OnThresholdReached(EventArgs e)
    {
     ThresholdReached?.Invoke(this, e);
    }
    
    Protected Overridable Sub OnThresholdReached(e As EventArgs)
     RaiseEvent ThresholdReached(Me, e)
    End Sub
    
  3. Call the raise method when the condition is met.

    Pass Empty because this event carries no data:

    if (_total >= _threshold)
    {
     OnThresholdReached(EventArgs.Empty);
    }
    
    If (_total >= _threshold) Then
     OnThresholdReached(EventArgs.Empty)
    End If
    
  4. Subscribe to the event using the += operator (in Visual Basic, AddHandler):

    c.ThresholdReached += c_ThresholdReached;
    
    AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
    
  5. Define the event handler method.

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

    static void c_ThresholdReached(object? sender, EventArgs e)
    {
     Console.WriteLine("The threshold was reached.");
     Environment.Exit(0);
    }
    
    Sub c_ThresholdReached(sender As Object, e As EventArgs)
     Console.WriteLine("The threshold was reached.")
     Environment.Exit(0)
    End Sub
    

The following example shows the complete implementation:

class EventNoData
{
 static void Main()
 {
 Counter c = new(new Random().Next(10));
 c.ThresholdReached += c_ThresholdReached;

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

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

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

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

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

 public event EventHandler? ThresholdReached;
}
Module EventNoData

 Sub Main()
 Dim c As New Counter(New Random().Next(10))
 AddHandler c.ThresholdReached, AddressOf c_ThresholdReached

 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

 Sub c_ThresholdReached(sender As Object, e As EventArgs)
 Console.WriteLine("The threshold was reached.")
 Environment.Exit(0)
 End Sub
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
 If (_total >= _threshold) Then
 OnThresholdReached(EventArgs.Empty)
 End If
 End Sub

 Protected Overridable Sub OnThresholdReached(e As EventArgs)
 RaiseEvent ThresholdReached(Me, e)
 End Sub

 Public Event ThresholdReached As EventHandler
End Class

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 EventArgs.

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

    public class ThresholdReachedEventArgs : EventArgs
    {
     public int Threshold { get; set; }
     public DateTime TimeReached { get; set; }
    }
    
    Class ThresholdReachedEventArgs
     Inherits EventArgs
    
     Public Property Threshold As Integer
     Public Property TimeReached As Date
    End Class
    
  2. Declare the event using the EventHandler<TEventArgs> delegate, passing your event data class as the type argument:

    public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
    
    Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
    
  3. 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):

    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
     ThresholdReached?.Invoke(this, e);
    }
    
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
     RaiseEvent ThresholdReached(Me, e)
    End Sub
    
  4. Populate the event data object and call the raise method when the condition is met:

    if (_total >= _threshold)
    {
     ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
     args.Threshold = _threshold;
     args.TimeReached = DateTime.Now;
     OnThresholdReached(args);
    }
    
    If (_total >= _threshold) Then
     Dim args As New ThresholdReachedEventArgs With {
     .Threshold = _threshold,
     .TimeReached = Date.Now
     }
     OnThresholdReached(args)
    End If
    
  5. Subscribe to the event using the += operator (in Visual Basic, AddHandler):

    c.ThresholdReached += c_ThresholdReached;
    
    AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
    
  6. Define the event handler.

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

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

The following example shows the complete implementation:

class EventWithData
{
 static void Main()
 {
 CounterWithData c = new(new Random().Next(10));
 c.ThresholdReached += c_ThresholdReached;

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

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

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

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

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

 public event EventHandler<ThresholdReachedEventArgs>? ThresholdReached;
}

public class ThresholdReachedEventArgs : EventArgs
{
 public int Threshold { get; set; }
 public DateTime TimeReached { get; set; }
}
Module EventWithData

 Sub Main()
 Dim c As New CounterWithData(New Random().Next(10))
 AddHandler c.ThresholdReached, AddressOf c_ThresholdReached

 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

 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
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
 If (_total >= _threshold) Then
 Dim args As New ThresholdReachedEventArgs With {
 .Threshold = _threshold,
 .TimeReached = Date.Now
 }
 OnThresholdReached(args)
 End If
 End Sub

 Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
 RaiseEvent ThresholdReached(Me, e)
 End Sub

 Public Event ThresholdReached As EventHandler(Of ThresholdReachedEventArgs)
End Class

Class ThresholdReachedEventArgs
 Inherits EventArgs

 Public Property Threshold As Integer
 Public Property TimeReached As Date
End Class

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 EventHandler<TEventArgs> 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:

    public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
    
    Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)
    
  2. Declare the event using your custom delegate type instead of EventHandler<TEventArgs>:

    public event ThresholdReachedEventHandler? ThresholdReached;
    
    Public Event ThresholdReached As ThresholdReachedEventHandler
    
  3. 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):

    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    {
     ThresholdReached?.Invoke(this, e);
    }
    
    Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
     RaiseEvent ThresholdReached(Me, e)
    End Sub
    
  4. Populate the event data object and call the raise method when the condition is met:

    if (_total >= _threshold)
    {
     ThresholdReachedEventArgs args = new();
     args.Threshold = _threshold;
     args.TimeReached = DateTime.Now;
     OnThresholdReached(args);
    }
    
    If (_total >= _threshold) Then
     Dim args As New ThresholdReachedEventArgs With {
     .Threshold = _threshold,
     .TimeReached = Date.Now
     }
     OnThresholdReached(args)
    End If
    
  5. Subscribe to the event using the += operator (in Visual Basic, AddHandler):

    c.ThresholdReached += c_ThresholdReached;
    
    AddHandler c.ThresholdReached, AddressOf c_ThresholdReached
    
  6. 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:

    static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    {
     Console.WriteLine($"The threshold of {e.Threshold} was reached at {e.TimeReached}.");
     Environment.Exit(0);
    }
    
    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
    

The following example shows the complete implementation:

class EventWithDelegate
{
 static void Main()
 {
 CounterWithDelegate c = new(new Random().Next(10));
 c.ThresholdReached += c_ThresholdReached;

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

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

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

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

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

 public event ThresholdReachedEventHandler? ThresholdReached;
}

public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
Module EventWithDelegate

 Sub Main()
 Dim c As New CounterWithDelegate(New Random().Next(10))
 AddHandler c.ThresholdReached, AddressOf c_ThresholdReached

 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

 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
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
 If (_total >= _threshold) Then
 Dim args As New ThresholdReachedEventArgs With {
 .Threshold = _threshold,
 .TimeReached = Date.Now
 }
 OnThresholdReached(args)
 End If
 End Sub

 Protected Overridable Sub OnThresholdReached(e As ThresholdReachedEventArgs)
 RaiseEvent ThresholdReached(Me, e)
 End Sub

 Public Event ThresholdReached As ThresholdReachedEventHandler
End Class

Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)

Related content


Feedback

Was this page helpful?

Additional resources