Events in C# are a fundamental part of creating responsive, interactive applications. They enable your application to notify other components when specific actions or changes occur. Events are particularly useful in building event-driven applications, such as graphical user interfaces, where user interactions like button clicks and keyboard inputs drive application behavior.
In this tutorial, we’ll explore how to define and work with events, discuss practical use cases, and walk through real-world examples to illustrate how events are commonly used in application development.
An event in C# is a mechanism for a class or an object to notify other classes or objects when something of interest occurs. Events are essentially a way of broadcasting that "something happened" so that other code can respond to it. They are widely used in application development to handle things like user actions, data changes, or system notifications.
In C#, events are built on delegates, which are references to methods. Delegates define the signature of the event handler methods that subscribe to the event.
The syntax for declaring an event in C# involves defining a delegate type for the event handlers and then declaring the event itself using this delegate type. Here’s a basic structure:
public delegate void EventHandlerType(object sender, EventArgs e);
public class MyEventPublisher
{
public event EventHandlerType MyEvent;
protected virtual void OnMyEvent(EventArgs e)
{
MyEvent?.Invoke(this, e);
}
}
OnMyEvent
, this method triggers the event if there are any subscribers.To work with events:
+=
and unsubscribe using -=
.using System;
public delegate void Notify(); // Delegate declaration
public class Process
{
public event Notify ProcessCompleted; // Event declaration
public void StartProcess()
{
Console.WriteLine("Process Started.");
OnProcessCompleted(); // Raise the event
}
protected virtual void OnProcessCompleted()
{
ProcessCompleted?.Invoke(); // Invoke event
}
}
public class Program
{
public static void Main()
{
Process process = new Process();
process.ProcessCompleted += ProcessCompletedHandler; // Event subscription
process.StartProcess(); // Start the process, triggers event
}
public static void ProcessCompletedHandler()
{
Console.WriteLine("Process Completed!");
}
}
Notify
is a delegate with no parameters.ProcessCompleted
is an event based on Notify.ProcessCompletedHandler
is the event handler that prints a message when the process completes.In UI applications, a common event is a button click. This example demonstrates how to define an event and then respond to a button click.
using System;
public class Button
{
public event EventHandler Click; // Event using EventHandler delegate
public void OnClick()
{
Click?.Invoke(this, EventArgs.Empty); // Raise event
}
}
public class Program
{
public static void Main()
{
Button button = new Button();
button.Click += ButtonClickHandler; // Subscribe to the event
button.OnClick(); // Simulate button click
}
private static void ButtonClickHandler(object sender, EventArgs e)
{
Console.WriteLine("Button was clicked!");
}
}
EventHandler
, a built-in delegate that takes an object and EventArgs
.ButtonClickHandler
is triggered when OnClick()
is called, simulating a button click event.Events often pass custom data to event handlers. Here’s an example of creating a custom EventArgs
class.
using System;
public class CustomEventArgs : EventArgs
{
public string Message { get; }
public CustomEventArgs(string message)
{
Message = message;
}
}
public class Messenger
{
public event EventHandler<CustomEventArgs> MessageSent;
public void SendMessage(string message)
{
OnMessageSent(new CustomEventArgs(message));
}
protected virtual void OnMessageSent(CustomEventArgs e)
{
MessageSent?.Invoke(this, e);
}
}
public class Program
{
public static void Main()
{
Messenger messenger = new Messenger();
messenger.MessageSent += MessageReceivedHandler;
messenger.SendMessage("Hello, world!");
}
private static void MessageReceivedHandler(object sender, CustomEventArgs e)
{
Console.WriteLine("Received message: " + e.Message);
}
}
CustomEventArgs
extends EventArgs
to pass a message.MessageReceivedHandler
receives the message when SendMessage
is called, demonstrating how events pass custom data.Imagine a simple chat application where the user sends a message, and the application updates the chat window to display it. We can use an event to notify the chat window when a new message is sent.
using System;
public class ChatMessageEventArgs : EventArgs
{
public string UserName { get; }
public string Message { get; }
public ChatMessageEventArgs(string userName, string message)
{
UserName = userName;
Message = message;
}
}
public class ChatUser
{
public event EventHandler<ChatMessageEventArgs> MessageSent;
public void SendMessage(string userName, string message)
{
OnMessageSent(new ChatMessageEventArgs(userName, message));
}
protected virtual void OnMessageSent(ChatMessageEventArgs e)
{
MessageSent?.Invoke(this, e);
}
}
public class ChatWindow
{
public void DisplayMessage(object sender, ChatMessageEventArgs e)
{
Console.WriteLine($"{e.UserName}: {e.Message}");
}
}
public class Program
{
public static void Main()
{
ChatUser user = new ChatUser();
ChatWindow window = new ChatWindow();
user.MessageSent += window.DisplayMessage;
user.SendMessage("Alice", "Hello, everyone!");
}
}
ChatMessageEventArgs
holds the username
and message
content.ChatUser
raises an event MessageSent
when a user sends a message.ChatWindow
listens for this event and displays the message, providing a simplified model of a chat application.+=
and unsubscribed with -=
.EventArgs
, events can pass custom data to handlers, making them more flexible.Events in C# are a powerful tool for creating interactive, event-driven applications. They enable components to communicate effectively, handling specific actions like user input, data changes, and more. By understanding how to declare and use events, you can build responsive applications that can easily adapt to user interactions and system events. Whether for a button click in a UI or a notification in a messaging app, events make it easy to create clear and maintainable code that responds to specific triggers, enhancing the functionality and interactivity of your C# applications.