Here is an example of a typical convention followed for setting up standard .Net events:
using System;
namespace ObserverExample
{
class Program
{
static void Main(string[] args)
{
var subject = new Subject();
var observer = new Observer();
observer.Observe(subject);
subject.SomeAction();
Console.ReadLine();
}
}
public class Subject
{
public event EventHandler<TopicEventArgs> TopicHappening;
public void SomeAction()
{
OnTopicHappening(new TopicEventArgs("Hello, observers!"));
}
protected virtual void OnTopicHappening(TopicEventArgs topicEventArgs)
{
EventHandler<TopicEventArgs> handler = TopicHappening;
if (handler != null)
handler(this, topicEventArgs);
}
}
public class TopicEventArgs : EventArgs
{
public TopicEventArgs(string message)
{
Message = message;
}
public string Message { get; private set; }
}
public class Observer
{
public void Observe(Subject subject)
{
subject.TopicHappening += subject_TopicHappening;
}
void subject_TopicHappening(object sender, TopicEventArgs e)
{
Console.WriteLine(e.Message);
}
}
}
The three primary classes involved in this example are the Subject
, Observer
, and the TopicEventArgs
. The Program
class serves only to provide a driver for the example.
Looking first at the Program.Main() method, instances of Subject (the object that will be raising events) and Observer (the object that will be subscribing to the raised events) are first instantiated. Next, the observer is passed an instance of the subject allowing it the opportunity to subscribe to any desired events. Lastly, the subject's SomeAction() method is called which results in the raising of the event.
Looking at the Subject, we see that an event named TopicHappening of type EventHandler<TopicEventArgs>
is publicly declared. The EventHandler type was introduced in .Net 2.0 and allows events to be declared without having to explicitly define delegate types. The Subject class also has two methods, SomeAction()
and OnTopicHappening()
. The method SomeAction()
represents the point within the application where the Subject performs some task for which it wants to notify the world (i.e. "any observers") about. The method OnTopicHappening(TopicEventArgs)
method provides the logical point within the class where the event will be raised. First, notice that it follows the naming convention On[Name of the event]. While this method can be named anything, this pattern has been widely adopted by convention. Second, notice that it is defined to take a single argument of type TopicEventArgs. This also follows a standard convention and serves the purpose of keeping the decision of what event arguments are raise at the logical point the event is raised (within the SomeAction() method) rather than from the physical point where the event is raised. Third, notice that it is declared protected virtual. This pattern is generally followed to allow any classes extending Subject to override what exactly happens when the TopicHappening event is raised.
Within the OnTopicHappening() method, the TopicHappening event is assigned to a separate variable before the event is checked for null and invoked. This is to avoid a possible race condition where the event may be cleared by another thread (i.e. all observers unsubscribed) after the check for null, but before the event is invoked.
Looking at the TopicEventArgs class, this represents the event topic our subject raises. A custom EventArgs class is generally created when the subject needs to associate information with the event being raised. For subjects which only wish to send a signal event without any associated arguments, the base EventArgs.Empty class should be used.
Lastly, the Observer class defines the objects which will receive the event notifications from the Subject. In this example, the Observer class exposes an Observe() method just as a way to receive a reference to an instance of Subject. Within the method, a private event handler method named subject_TopicHappening is assigned to the TopicHappening event on the subject. This name format is the result of the delegate automatically generated by Visual Studio upon typing += when registering to handle the event. This essentially adds this method to the collection of methods to invoke when the event is raised by the subject. When invoked, the private subject_TopicHappening method simply writes the message contained within the event arguments out to the Console.
Hope this helps.