Event system is central part of a software system. For example, button can fire clicked event. Batch job can generate job complete events. Student system would use registration events.
In event system, there would be two roles: broadcaster and subscriber.
The broadcaster is a type that contains a delegate
field.
The broadcaster decides
when to broadcast, by invoking the delegate
.
The subscribers are the method target recipients.
A subscriber decides when to start and stop listening, by calling += and -= on the broadcaster's delegate.
Events are a C# language feature that formalizes this pattern.
To declare an event, put the event
keyword in front of a delegate
member:
// a delegate public delegate void ValueChangedHandler (decimal oldPrice, decimal newPrice); public class Broadcaster { // Event declaration public event ValueChangedHandler PriceChanged; }
Code within the Broadcaster
type has full access
to PriceChanged
and can treat it as
a delegate.
Code outside of Broadcaster can only perform +=
and -=
operations on
the PriceChanged
event.
The .NET Framework defines a standard pattern for writing events.
System.EventArgs
is a predefined Framework class with no members.
EventArgs
is a base class for carrying
information for an event.
The following code subclasses
EventArgs
to store the old and new prices when a PriceChanged
event is fired:
public class PriceChangedEventArgs : System.EventArgs { public readonly decimal LastPrice; public readonly decimal NewPrice; public PriceChangedEventArgs (decimal lastPrice, decimal newPrice) { LastPrice = lastPrice; NewPrice = newPrice; } }
The EventArgs
subclass is named according to the information it
contains.
It typically exposes data as properties or as read-only fields.
After creating the EventArgs
subclass, the next step is to define a delegate
for the event which is the event handler delegate.
The event handler delegate must have a void return type.
The event handler delegate must accept two arguments: the first of type object, and the second a subclass of EventArgs.
The first argument indicates the event broadcaster, and the second argument contains the extra information to convey.
The event handler delegate's name must end with EventHandler
.
The Framework defines a generic delegate called System.EventHandler<>
that satisfies
these rules:
public
delegate
void
EventHandler<TEventArgs> (object source, TEventArgs e)
where TEventArgs : EventArgs;
The following code defines the delegate for our value changed event.
public delegate void ValueChangedHandler (object sender, PriceChangedEventArgs e);
The next step is to define an event of the chosen delegate type.
Here, we use the
generic EventHandler
delegate:
public class Product { public event EventHandler<PriceChangedEventArgs> PriceChanged; }
Finally, the pattern requires that you write a protected virtual method that fires the event.
The name must match the name of the event, prefixed with the word On
and accept a single EventArgs
argument:
public class Product { ... public event EventHandler<PriceChangedEventArgs> PriceChanged; protected virtual void OnPriceChanged (PriceChangedEventArgs e) { if (PriceChanged != null) PriceChanged (this, e); } }
Here's the complete example:
using System;/*www . j a va 2s . com*/
public class PriceChangedEventArgs : EventArgs {
public readonly decimal LastPrice;
public readonly decimal NewPrice;
public PriceChangedEventArgs (decimal lastPrice, decimal newPrice) {
LastPrice = lastPrice; NewPrice = newPrice;
}
}
public class Product {
string symbol;
decimal price;
public Product (string symbol) {
this.symbol = symbol;
}
public event EventHandler<PriceChangedEventArgs> PriceChanged;
protected virtual void OnPriceChanged (PriceChangedEventArgs e) {
if (PriceChanged != null) {
PriceChanged (this, e);
}
}
public decimal Price {
get {
return price;
}
set {
if (price == value) return;
decimal oldPrice = price;
price = value;
OnPriceChanged (new PriceChangedEventArgs (oldPrice, price));
}
}
}
class Test {
static void Main() {
Product stock = new Product ("THPW");
stock.Price = 2.10M;
// Register with the PriceChanged event
stock.PriceChanged += stock_PriceChanged;
stock.Price = 3.9M;
}
static void stock_PriceChanged (object sender, PriceChangedEventArgs e) {
if (e.NewPrice - e.LastPrice > 0){
Console.WriteLine ("Alert!");
}
}
}
An event's accessors are the implementations
of its +=
and -=
functions.
By default, accessors are implemented implicitly by the compiler.
Like methods, events can be virtual, overridden, abstract, or sealed.
Events can also be static:
public class Product {
public static event EventHandler<EventArgs> StaticEvent;
public virtual event EventHandler<EventArgs> VirtualEvent;
}