;

C# Events


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.

What are Events in C#?

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.

Common Uses for Events

  • User Interface: Handling button clicks, key presses, or mouse movements.
  • Data Changes: Notifying other parts of an application when data has been modified.
  • Error Handling: Triggering alerts or logging in response to system errors.

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.

Syntax of Events in C#

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);
    }
}
  • Delegate: Declares the signature that event handler methods should follow.
  • Event: The actual event, declared using the delegate type.
  • Invoker Method: Often called OnMyEvent, this method triggers the event if there are any subscribers.

Working with Events and Delegates

To work with events:

  1. Define a delegate that specifies the event handler's signature.
  2. Declare an event based on this delegate.
  3. Subscribe to the event using += and unsubscribe using -=.
  4. Raise the event to notify subscribers when the event occurs.

Example: Basic Event Declaration and Subscription

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!");
    }
}

Explanation:

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

Examples of Events in Action

Example 1: Button Click Event

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!");
    }
}

Explanation:

  • The Click event is of type EventHandler, a built-in delegate that takes an object and EventArgs.
  • ButtonClickHandler is triggered when OnClick() is called, simulating a button click event.

Example 2: Event with Custom Event Arguments

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);
    }
}

Explanation:

  • CustomEventArgs extends EventArgs to pass a message.
  • MessageReceivedHandler receives the message when SendMessage is called, demonstrating how events pass custom data.

Real-World Example: Event Handling in a User Interface

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.

Example: Chat Application Event

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!");
    }
}

Explanation:

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

Key Takeaways

  • Events Enable Responsive Applications: Events allow classes to respond to changes and actions, making applications more interactive.
  • Built on Delegates: Events use delegates to specify the method signatures for event handlers.
  • Event Subscription: Handlers are subscribed using += and unsubscribed with -=.
  • Custom Event Arguments: By extending EventArgs, events can pass custom data to handlers, making them more flexible.

Summary

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.