Events

An event is a notification. By necessity, this definition is broad. Events encompass a wide range of occurrences and actions. Here is a description of some predefined events, which underscores the breadth of activities. A button-click event notifies a form that a button has been clicked. A timer event is a notification that a set period of time has elapsed. The unhandled exception event of the application domain is a notification of a fatal exception. The Application_Start event notifies a Web application that the application is loading. You also can create custom events for a variety of purposes. Typically an event is exposed as a member of a publisher class, such as a button class.

Anyone interested in an event can subscribe to that event. Subscribers register for an event by adding a delegate to the event. The delegate must contain a single function reference. The publisher notifies the subscriber by calling the function reference of the delegate. The subscriber’s response to the event is coded in the function. When the event is raised, the publisher calls the function, affording the subscriber an opportunity to respond to or handle the event. For this reason, the function is called an event handler. Events can have multiple subscribers. For example, a building class could have a fire alarm event. Everyone in the building might want to subscribe to that event!

What happens when there are no subscribers to a particular event? In other words, if a tree falls in the woods and no one hears it, does it make a sound? If the tree is an event, no sound is made. If an event has no subscribers, no one is notified.

Publishing an Event

Both classes and objects can own events. Classes can publish events as static members, whereas objects publish events as instance members. Multicast delegates underlie events. Events are defined with the event keyword. Here is the syntax for defining an event:

accessibility event delegatename eventname

The accessibility of an event is typically public or protected, although private events are sometimes seen. Protected events restrict subscribers to children. A public event is available to any interested subscriber. The delegate name is the underlying delegate of the event. The delegate defines the signature of the event handler. Subscribers can subscribe only with delegates of a compatible signature. Here is some sample code:

public delegate void DelegateClass();
public event DelegateClass MyEvent;

As a best practice, event handlers should return void and have two arguments. The first parameter is the object that raised the event. The second parameter is an object derived from EventArgs having optional data that further explains the event. EventHandler is a predefined delegate that matches this signature. It is included in the .NET Framework Class Library (FCL) and frees you from having to declare a separate delegate for a standard event.

A field is added to the surrounding class in support of the event. The field has the same type as the underlying delegate. The C# compiler also adds methods to add and remove subscribers to the event. The names of the methods are add_<EventName> and remove_<EventName>, respectively. The event itself is also present in the class. Figure 10-5 shows an internal view of a class that contains an event.

A class with an event and related members

Figure 10-5. A class with an event and related members

Subscribers

The publisher/subscriber relationship supports a one-to-many or many-to-many relationship. For each publisher, there can be zero or more subscribers. Conversely, a subscriber can subscribe to multiple different events. For example, a form can subscribe to a button-click and a text-change event. Subscribers register for an event by adding a delegate to the event. The delegate includes a function reference to be called when the event is raised, which is how the subscriber is notified. Subscribe to an event using the add method or the += compound assignment operator (eventname += delegatename), as shown in the following sample code:

using System;

namespace Donis.CSharpBook {
    class Publisher {
        public event EventHandler MyEvent;
    }

    public class Subscriber {

        public static void Handler(object obj, EventArgs args) {
        }

        public static void Main() {
            Publisher pub = new Publisher();
            pub.MyEvent += Handler;
            // other processing
        }
    }
}

Subscribers can unregister for an event with the -= compound assignment operator (eventname -= delegatename).

Raising an Event

Publishers raise an event to notify subscribers that something has occurred, by calling an event handler in the subscriber. The publisher should not raise an event when there are no subscribers. Raising an event for no subscribers causes an exception. Events with no subscribers are null, which can be tested. Raise an event with the call operator ( ). Just as with a delegate, you also can execute (or raise) an event with the Invoke method. The parameters of an event are passed as arguments to the event handlers. The return value of an event is set by the last event handler. Here is an example of the proper way to raise an event:

class Publisher {
    public event EventHandler MyEvent;

    public void SomeMethod() {
        if (MyEvent != null) {
            MyEvent(null, null);
        }
    }
}

EventArgs

Publishers sometimes provide subscribers additional information pertaining to an event. This valuable information is found in the EventArgs-derived class, which is typically the second parameter of the event. For example, the MouseEventArgs class provides the x and y coordinates of the mouse pointer for a mouse- click event. The DataRowChangeEventArgs class provides the row and action for database-related events, such as the RowChanged event. The PaintEventArgs class provides the clip rectangle and graphics object for a paint event. MouseEventArgs, DataRowChangeEventArgs, and PaintEventArgs are derived from the EventArgs class.

The following is code for a bank account. The NSF event is raised when the account is overdrawn. The BankEventArgs class provides the bank account balance and the amount of the transaction that would overdraw the account:

using System;

namespace Donis.CSharpBook {

    public class Starter {
        public static void Main() {
            Bank account = new Bank();
            account.NSF += NSFHandler;
            account.Deposit(500);
            account.Withdrawal(750);
        }

        public static void NSFHandler(object o, BankEventArgs e) {
            Console.WriteLine("NSF Transaction");
            Console.WriteLine("Balance: {0}", e.Balance);
            Console.WriteLine("Transaction: {0}",
                e.Transaction);
        }
    }

    public delegate void OverDrawn(object o, BankEventArgs e);
    public class Bank {
        public event OverDrawn NSF; // non-sufficient funds

        public decimal Deposit(decimal amountDeposit) {
            propBalance += amountDeposit;
            return propBalance;
        }

        public decimal Withdrawal(decimal amountWithdrawn) {
            decimal newBalance = propBalance - amountWithdrawn;
            if (newBalance < 0) {
                if (NSF != null) {
                    BankEventArgs args = new BankEventArgs(
                        Balance, amountWithdrawn);
                    NSF(this, args);
                }
            }
            return propBalance = newBalance;
        }

        private decimal propBalance = 0;
        public decimal Balance {
            get {
                return propBalance;
            }
        }
    }

    public class BankEventArgs: EventArgs {

        public BankEventArgs(decimal amountBalance, decimal amountTransaction) {
            propBalance=amountBalance;
            propTransaction=amountTransaction;
        }

        private decimal propBalance;
        public decimal Balance {
            get {
                return propBalance;
            }
        }

        private decimal propTransaction;
        public decimal Transaction {
            get {
                return propTransaction;
            }
        }
    }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.70.38