C# Events

C# Events Explained

In C#, use the event keyword to declare events. An event is associated with a delegate type, allowing multiple methods to be called when the event is triggered. You can also specify access modifiers to control the event visibility, enhancing encapsulation.

using System;
public class Car
{
// Declare the event using a delegate type
public event EventHandler EngineStarted;
public void StartEngine()
{
Console.WriteLine("Engine started.");
// Trigger the event
EngineStarted?.Invoke(this, EventArgs.Empty);
}
}
class Program
{
static void Main()
{
Car car = new Car();
car.EngineStarted += (sender, e) => Console.WriteLine("Listener: The engine has been started!");
car.StartEngine();
}
}

C# Event Usage

C# leverages EventHandler<T> to handle events with specific data types, ensuring compile-time type safety. This method allows developers to prevent runtime errors by enforcing type consistency at compile time. In the snippet, note how MyEventArgs enforces type safety for our event data.

// Define event data class
public class MyEventArgs : EventArgs {
public string Message { get; set; }
}
// Define a class with an event
public class Publisher {
public event EventHandler<MyEventArgs> OnDataReceived;
public void RaiseEvent(string message) {
OnDataReceived?.Invoke(this, new MyEventArgs { Message = message });
}
}
// Subscriber class
public class Subscriber {
public void OnDataReceived(object sender, MyEventArgs e) {
Console.WriteLine($"Received message: {e.Message}");
}
}
// Usage Example
var publisher = new Publisher();
var subscriber = new Subscriber();
publisher.OnDataReceived += subscriber.OnDataReceived;
publisher.RaiseEvent("Hello, EventHandling!");

Raising Events in C#

In C#, events are raised using the Invoke() method after null checking. This ensures only subscribed methods are called when an event occurs. Use this to trigger actions across your application efficiently.

using System;
class AlarmClock {
public event EventHandler AlarmRang;
public void RingAlarm() {
AlarmRang?.Invoke(this, EventArgs.Empty); // Check for null and invoke
}
}
class Program {
static void Main() {
AlarmClock myClock = new AlarmClock();
myClock.AlarmRang += (sender, e) => Console.WriteLine("Alarm is ringing!");
myClock.RingAlarm();
}
}

C# Event Pattern

Events in C# enable communication between objects using the publisher-subscriber pattern. This allows one object, the publisher, to maintain a list of subscribers and notify them of changes, ensuring loose coupling. Above, an example demonstrates how an event can be created, published, and subscribed to.

using System;
public class Publisher {
// Declare the event using EventHandler
public event EventHandler EventOccurred;
public void TriggerEvent() {
Console.WriteLine("Event is about to occur!");
// Check if there are any subscribers
EventOccurred?.Invoke(this, EventArgs.Empty);
}
}
public class Subscriber {
public void OnEventOccurred(object sender, EventArgs e) {
Console.WriteLine("Event has been handled.");
}
}
public class Program {
public static void Main() {
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();
// Subscribe to the event
publisher.EventOccurred += subscriber.OnEventOccurred;
// Trigger the event
publisher.TriggerEvent();
}
}

C# Event Handlers

In C#, you use the += operator to subscribe and the -= operator to unsubscribe an event handler to an event. This allows your program to respond dynamically to events, like button clicks or data changes.

using System;
public class EventExample
{
public event EventHandler ButtonClicked;
public void ClickButton()
{
if (ButtonClicked != null)
ButtonClicked(this, EventArgs.Empty);
}
public static void Main(string[] args)
{
EventExample example = new EventExample();
// Subscribe to the event
example.ButtonClicked += Example_ButtonClicked;
// Trigger the event
example.ClickButton();
// Unsubscribe from the event
example.ButtonClicked -= Example_ButtonClicked;
}
private static void Example_ButtonClicked(object sender, EventArgs e)
{
Console.WriteLine("Button was clicked!");
}
}

C# Event Handlers

In C#, event handlers are implemented using method group conversions or lambda expressions that match a delegate signature. This allows for responsive, dynamic applications by handling events such as clicks and actions effectively. Use += to attach a handler to an event.

using System;
class Program {
static void Main() {
// Create a button
Button myButton = new Button();
// Attach an event handler using a method group
myButton.Click += ButtonClicked;
// Attach an event handler using a lambda expression
myButton.Click += (sender, e) => {
Console.WriteLine("Button clicked with lambda!");
};
// Simulate button click
myButton.SimulateClick();
}
// Event handler method
static void ButtonClicked(object sender, EventArgs e) {
Console.WriteLine("Button clicked!");
}
}
class Button {
// Define the Click event using EventHandler delegate
public event EventHandler Click;
// Method to simulate the button click
public void SimulateClick() {
Click?.Invoke(this, EventArgs.Empty);
}
}

C# Event Interfaces

In C#, interfaces can declare events that implementing classes must define. This ensures a consistent way to handle events across various classes, promoting uniformity and modularity in your code. Implementing classes guarantee they support and implement the events outlined by the interface, aiding structure and communication in complex applications.

public interface IEventNotifier {
event EventHandler Notify;
}
public class EventNotifier : IEventNotifier {
public event EventHandler Notify;
public void TriggerEvent() {
if (Notify != null) {
Notify(this, EventArgs.Empty);
}
}
}

C# Protected Events

In C#, use the protected virtual OnEventName() method to define and raise events in base classes. This pattern allows derived classes to override the method and handle events seamlessly. By default, this method checks for event subscribers, preventing null reference exceptions.

public class BaseClass
{
public event EventHandler MyEvent;
protected virtual void OnMyEvent()
{
// Check if there are subscribers
MyEvent?.Invoke(this, EventArgs.Empty);
}
}

C# Custom EventArgs

In C#, custom EventArgs classes inherit from the EventArgs base class to pass extra data when raising events. This allows sending specific data alongside standard event notifications by creating a new class derived from EventArgs.

using System;
// Define a custom EventArgs class
public class TemperatureChangedEventArgs : EventArgs
{
public double NewTemperature { get; }
public TemperatureChangedEventArgs(double newTemperature)
{
NewTemperature = newTemperature;
}
}
// Publisher class
public class Thermostat
{
public event EventHandler<TemperatureChangedEventArgs> TemperatureChanged;
private double _currentTemperature;
public double CurrentTemperature
{
get => _currentTemperature;
set
{
if (Math.Abs(_currentTemperature - value) > 0.01)
{
_currentTemperature = value;
OnTemperatureChanged(new TemperatureChangedEventArgs(value));
}
}
}
protected virtual void OnTemperatureChanged(TemperatureChangedEventArgs e)
{
TemperatureChanged?.Invoke(this, e);
}
}
// Subscriber example
public class Display
{
public void Register(Thermostat thermostat)
{
thermostat.TemperatureChanged += OnTemperatureChanged;
}
private void OnTemperatureChanged(object sender, TemperatureChangedEventArgs e)
{
Console.WriteLine($"Temperature changed to: {e.NewTemperature}°C");
}
}

C# EventHandler Pattern

The EventHandler delegate pattern in C# requires methods to include two specific parameters: object sender for the event source and EventArgs e for event data. This pattern standardizes how events are handled in applications, promoting consistency across event handling logic.

using System;
class Program
{
// Event declaration using EventHandler
public event EventHandler ExampleEvent;
// Method matching EventHandler signature
protected virtual void OnExampleEvent(EventArgs e)
{
ExampleEvent?.Invoke(this, e);
}
static void Main()
{
Program program = new Program();
// Subscribing to the event
program.ExampleEvent += (sender, e) =>
{
Console.WriteLine("Event Triggered!");
};
// Triggering the event
program.OnExampleEvent(EventArgs.Empty);
}
}

Learn more on Codecademy