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