C# -

Events

Events in C# are a powerful mechanism for building responsive and interactive applications. They provide a way for objects to communicate with each other by notifying subscribers when something of interest occurs. This tutorial covers the basics of events, their use cases, how to define and use them, and best practices.


1. Understanding Events

Events are a way for an object (the publisher) to notify other objects (the subscribers) that something has happened. This is achieved using delegates to provide a method signature for the event handlers.

Syntax:

public event EventHandler EventName;


2. Defining and Raising Events

To define an event, you use the event keyword followed by a delegate type. The event can then be raised using the Invoke method if there are any subscribers.

Example:
        
            namespace EventExamples;

public class Publisher
{
    // Define an event using EventHandler
    public event EventHandler SomethingHappened;

    public void DoSomething()
    {
        // Raise the event
        SomethingHappened?.Invoke(this, EventArgs.Empty);
    }
}

public class Subscriber
{
    public void OnSomethingHappened(object sender, EventArgs e)
    {
        Console.WriteLine("Event received.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Publisher publisher = new Publisher();
        Subscriber subscriber = new Subscriber();

        // Subscribe to the event
        publisher.SomethingHappened += subscriber.OnSomethingHappened;

        // Trigger the event
        publisher.DoSomething();
    }
}
        
    

3. Subscribing to and Unsubscribing from Events

Subscribers can attach their event handlers to the event using the += operator and detach using the -= operator.

Example:
        
            namespace EventExamples;

public class Publisher
{
    public event EventHandler SomethingHappened;

    public void DoSomething()
    {
        SomethingHappened?.Invoke(this, EventArgs.Empty);
    }
}

public class Subscriber
{
    public void OnSomethingHappened(object sender, EventArgs e)
    {
        Console.WriteLine("Event received.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Publisher publisher = new Publisher();
        Subscriber subscriber = new Subscriber();

        // Subscribe to the event
        publisher.SomethingHappened += subscriber.OnSomethingHappened;

        // Trigger the event
        publisher.DoSomething();

        // Unsubscribe from the event
        publisher.SomethingHappened -= subscriber.OnSomethingHappened;

        // Trigger the event again (no output expected)
        publisher.DoSomething();
    }
}
        
    

4. Custom Event Arguments

Events often need to provide additional data to the event handlers. This can be done by defining a custom event arguments class that inherits from EventArgs.

Example:
        
            namespace EventExamples;

// Define custom event arguments
public class CustomEventArgs : EventArgs
{
    public string Message { get; }

    public CustomEventArgs(string message)
    {
        Message = message;
    }
}

public class Publisher
{
    public event EventHandler<CustomEventArgs> SomethingHappened;

    public void DoSomething(string message)
    {
        SomethingHappened?.Invoke(this, new CustomEventArgs(message));
    }
}

public class Subscriber
{
    public void OnSomethingHappened(object sender, CustomEventArgs e)
    {
        Console.WriteLine($"Event received with message: {e.Message}");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Publisher publisher = new Publisher();
        Subscriber subscriber = new Subscriber();

        // Subscribe to the event
        publisher.SomethingHappened += subscriber.OnSomethingHappened;

        // Trigger the event
        publisher.DoSomething("Hello, Events!");
    }
}
        
    

5. Advanced Event Patterns

The .NET Framework defines a standard pattern for events called the Event-based Asynchronous Pattern (EAP), which includes best practices for defining and raising events, including the use of EventHandler and EventHandler<TEventArgs>.

Example:
        
            namespace EventExamples;

// Define custom event arguments
public class ProgressEventArgs : EventArgs
{
    public int PercentComplete { get; }

    public ProgressEventArgs(int percentComplete)
    {
        PercentComplete = percentComplete;
    }
}

public class Worker
{
    // Use EventHandler<T> for custom event arguments
    public event EventHandler<ProgressEventArgs> ProgressChanged;

    public void StartWork()
    {
        for (int i = 0; i <= 100; i += 10)
        {
            // Simulate work
            System.Threading.Thread.Sleep(100);

            // Raise the event
            OnProgressChanged(i);
        }
    }

    protected virtual void OnProgressChanged(int percentComplete)
    {
        ProgressChanged?.Invoke(this, new ProgressEventArgs(percentComplete));
    }
}

public class ProgressBar
{
    public void OnProgressChanged(object sender, ProgressEventArgs e)
    {
        Console.WriteLine($"Progress: {e.PercentComplete}%");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Worker worker = new Worker();
        ProgressBar progressBar = new ProgressBar();

        // Subscribe to the event
        worker.ProgressChanged += progressBar.OnProgressChanged;

        // Start the work
        worker.StartWork();
    }
}
        
    

6. Where to Use Events


7. Where Not to Use Events


8. Best Practices for Using Events



Conclusion

Events in C# provide a powerful mechanism for building interactive and responsive applications. By understanding how to define, raise, and handle events, as well as when and where to use them, you can create flexible and maintainable software.