A Deep Dive into C# Events

Introduction

Events in C# are a way for a class to provide notifications to clients of that class when some interesting thing happens to an object. The most familiar use for events is in graphical user interfaces; typically, the classes that represent controls in the interface have events that are notified when the user does something to the control (for example, click a button).

1. What is an Event?

In C#, an event is a mechanism through which a class (publisher) can notify its consumers (subscribers) of a change or activity. The publisher determines when to trigger the event, and the subscribers determine what action to take in response.

Events are based on the delegate model in C#.

2. How to Use Events?

Here's a step-by-step guide:

2.1 Declare a delegate

The delegate will define the signature of the event handlers.

public delegate void Notify();  // Delegate declaration

2.2 Declare the event using the delegate

public event Notify ProcessCompleted;  // Event declaration

2.3 Raise the event

protected virtual void OnProcessCompleted()
{
    ProcessCompleted?.Invoke();
}

3. A Simple Example

Here’s an example of how to create and use events:

public class ProcessBusinessLogic
{
    public delegate void ProcessCompletedEventHandler();
    public event ProcessCompletedEventHandler ProcessCompleted;

    public void StartProcess()
    {
        Console.WriteLine("Process Started!");
        // Some processing logic...

        OnProcessCompleted();
    }

    protected virtual void OnProcessCompleted()
    {
        ProcessCompleted?.Invoke();
    }
}

public class MainClass
{
    public static void Main(string[] args)
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        bl.ProcessCompleted += bl_ProcessCompleted;  // Register with an event
        bl.StartProcess();
    }

    // Event handler
    public static void bl_ProcessCompleted()
    {
        Console.WriteLine("Process Completed!");
    }
}

4. Events with EventArgs

Using EventArgs, you can pass custom information when the event is triggered.

public class ProcessEventArgs : EventArgs
{
    public string Message { get; set; }
}

public class ProcessBusinessLogic
{
    public delegate void ProcessCompletedEventHandler(object sender, ProcessEventArgs e);
    public event ProcessCompletedEventHandler ProcessCompleted;

    public void StartProcess()
    {
        Console.WriteLine("Process Started!");

        OnProcessCompleted(new ProcessEventArgs { Message = "Process Finished!" });
    }

    protected virtual void OnProcessCompleted(ProcessEventArgs e)
    {
        ProcessCompleted?.Invoke(this, e);
    }
}

public class MainClass
{
    public static void Main(string[] args)
    {
        ProcessBusinessLogic bl = new ProcessBusinessLogic();
        bl.ProcessCompleted += bl_ProcessCompleted;
        bl.StartProcess();
    }

    public static void bl_ProcessCompleted(object sender, ProcessEventArgs e)
    {
        Console.WriteLine(e.Message);
    }
}

5. Using EventHandler Delegate

Instead of declaring a custom delegate, C# provides a generic EventHandler delegate, which you can use for most events.

public class ProcessBusinessLogic
{
    public event EventHandler<ProcessEventArgs> ProcessCompleted;

    public void StartProcess()
    {
        Console.WriteLine("Process Started!");

        OnProcessCompleted(new ProcessEventArgs { Message = "Process Done!" });
    }

    protected virtual void OnProcessCompleted(ProcessEventArgs e)
    {
        ProcessCompleted?.Invoke(this, e);
    }
}

6. Anonymous Methods and Lambda Expressions with Events

You can also use anonymous methods or lambda expressions to handle events:

ProcessBusinessLogic bl = new ProcessBusinessLogic();
bl.ProcessCompleted += (sender, e) => 
{
    Console.WriteLine(e.Message);
};
bl.StartProcess();

Conclusion

Events are a fundamental concept in C# (and .NET in general) that facilitate a decoupled design between objects. They allow objects to communicate without needing to reference each other directly. By understanding and effectively using events, developers can create systems that are more modular, maintainable, and scalable.