Event handling is essentially a process by which one object can notify other objects that an event has occurred. This process is largely encapsulated by multicast delegates, which have this ability built-in.
The .NET Framework defines many event-handling delegates for you, but you can write your own. For example:
delegate void MoveEventHandler(object source, MoveEventArgs e);
By convention, an event delegate’s first parameter denotes the
source of the event, and the delegate’s second parameter
derives from System. EventArgs
and stores data about the event.
The
EventArgs
class
can be derived from to include information relevant to a particular
event:
public class MoveEventArgs : EventArgs { public int newPosition; public bool cancel; public MoveEventArgs(int newPosition) { this.newPosition = newPosition; } }
A class or struct can declare an event by
applying the event modifier to a delegate field. In this example, the
Slider
class has a Position
property that fires a Move
event whenever its
Position
changes:
class Slider { int position; public event MoveEventHandler Move; public int Position { get { return position; } set { if (position != value) { // if position changed if (Move != null) { // if invocation list not empty MoveEventArgs args = new MoveEventArgs(value); Move(this, args); // fire event if (args.cancel) return; } position = value; } } } }
The event
keyword promotes encapsulation by
ensuring that only the +=
and
-=
operations can be performed on the delegate.
This means other classes can register themselves to be notified of
the event, but only the Slider
can invoke the
delegate (fire the event) or clear the delegate’s invocation
list.
You can act on an event by adding an event handler to an event. An event handler is a delegate that wraps the method you want invoked when the event is fired.
In the next example, we want our Form
to act on
changes made to a Slider
’s
Position
. You do this by creating a
MoveEventHandler
delegate that wraps the
event-handling method, the slider.Move
method.
This delegate is added to the Move
event’s
existing list of MoveEventHandler
s (which starts
off empty). Changing the position on the Slider
object fires the Move
event, which invokes the
slider.Move
method:
class Form { static void Main( ) { Slider slider = new Slider( ); // register with the Move event slider.Move += new MoveEventHandler(slider_Move); slider.Position = 20; slider.Position = 60; } static void slider_Move(object source, MoveEventArgs e) { if(e.newPosition < 50) Console.WriteLine("OK"); else { e.cancel = true; Console.WriteLine("Can't go that high!"); } } }
Typically the Slider
class would be enhanced to
fire the Move
event whenever its
Position
is changed by a mouse movement, keypress,
or other user action.
attributes
?
access-modifier
?
|
new?
static?
|
event
delegate type event-property-name
|
attributes
?
get
statement-block
|
attributes
?
set
statement-block
|
} |
Although it is convenient to modify a delegate field with the event modifier, it can be inefficient. For instance, a class with 100 events can store 100 delegate fields, even though typically only four of those events are actually assigned. Instead, you can store these delegates in a collection such as a hashtable and use a property rather than a field to expose the event:
public event MoveEventHandler Move { get { return (MoveEventHandler)myEventStorer["Move"]; } set { myEventStore ["Move"] = value; } }
3.144.97.126