Advanced Event-Based Programming

At this point, if the discussion of programming ended with events, you would have enough information to continue through the rest of the book and nothing that Windows Forms or ASP.NET do related to events would seem unfamiliar to you.

Many techniques that can be applied to event programming will produce some pretty amazing results. For example, one such technique is the use of the add and remove accessors on an event. Just as properties have a get and set accessor, events have their own accessors that allow you to write code that will be executed when a client subscribes to an event and when a client unsubscribes from the event. The power that these accessors give your code is incredible. For example, if you have written some code that exposes events over a network using Remoting, you can write code inside the "add" accessor that allows you to detect when a network client subscribes to an event. Likewise, you can detect when a network client unsubscribes, giving you immediate access to that information.

There also may be scenarios when you don't want an event to be fired to all subscribing clients. Take the hypothetical scenario where you have created an event-driven application. The application consists of a central server and multiple clients. Each client subscribes to an event that indicates some data has changed. However, this data is secured at the row level, and not all clients should be able to see it. To maximize security, your application is not even allowed to transmit data over a wire that the client cannot see. To accomplish this using event-based programming, you need to be able to programmatically filter which event targets receive the event and which targets do not.

Each delegate has a Target property, which indicates the object that houses the method that will be invoked by the delegate. A trick that I find extremely helpful is that if the code knows the data type of the subscribing class, it can use that information to determine if the delegate should be invoked on that object or not, as shown in the following snippet of code:

if (  ((Customer)myDelegate.Target).CustomerID == 12)     // invoke method 

The code in Listing 9.5 is a complete sample that demonstrates the use of the add and remove accessors, as well as the selective invocation of methods on event subscribers.

Listing 9.5. Advanced Event Programming Sample

using System; using System.Collections.Generic; using System.Text; namespace AdvancedEvent { delegate void NameChangedDelegate(string name, string newValue); class Program { static void Main(string[] args) {     Customer c = new Customer();     Subscriber s1 = new Subscriber(c, "subscriber-A");     Subscriber s2 = new Subscriber(c, "subscriber-B");     Subscriber s3 = new Subscriber(c, "subscriber-C");     c.FirstName = "Kevin";     c.LastName = "Hoffman";     s2.Unsubscribe();     c.FirstName = "Joe";     c.MiddleName = "Scott";     Console.ReadLine(); } } class Subscriber { private string subscriberId = "new subscriber"; private Customer myCustomer = null; private NameChangedDelegate ncDel = null; public Subscriber(Customer c, string subId) {     subscriberId = subId;     ncDel = new NameChangedDelegate(myCustomer_OnNameChanged);     myCustomer = c;     myCustomer.OnNameChanged += ncDel; } void myCustomer_OnNameChanged(string name, string newValue) {     Console.WriteLine("[{0}] Customer {1} changed to {2}.", subscriberId,         name, newValue); } public void Unsubscribe() {     myCustomer.OnNameChanged -= ncDel; } public string SubscriberID {     get     {         return subscriberId;     }     set     {         subscriberId = value;     } } } class Customer { private string firstName; private string lastName; private string middleName; private event NameChangedDelegate onNameChange; public event NameChangedDelegate OnNameChanged {     add     {         onNameChange += value;         if (value.Target is Subscriber)         {             Console.WriteLine( "Subscriber '{0}' just subscribed to OnNameChanged.",                 ((Subscriber)value.Target).SubscriberID);         }     }     remove     {         onNameChange -= value;         if (value.Target is Subscriber)         {             Console.WriteLine( "Subscriber '{0}' just un-subscribed from OnNameChanged.",                 ((Subscriber)value.Target).SubscriberID);         }     } } public string FirstName {     get { return firstName; }     set     {         firstName = value;         onNameChange("firstname", value);     } } public string LastName {     get { return lastName; }     set     {         lastName = value;         onNameChange("lastname", value);     } } public string MiddleName {     get { return MiddleName; }     set     {         middleName = value;         NotifyAllBut("subscriber-C", "middlename", value);     } } private void NotifyAllBut(string subId, string name, string value) {     foreach (NameChangedDelegate d in onNameChange.GetInvocationList())     {         if (((Subscriber)d.Target).SubscriberID.ToUpper() != subId.ToUpper())         {             d(name, value);         }     } } } } 

The first thing that should be noted about the preceding code is that the add and remove accessors are used to print out some informative messages indicating when a class subscribes or unsubscribes from the event. Also note that in these accessors, the Target property is used to print out the SubscriberID of the class subscribing to or unsubscribing from the event.

Next, the NotifyAllBut method will invoke all the subscribing methods to an event except the event handler hosted by a Subscriber class whose subscriber ID is 'subscriber-C'. This is proven in the console output of the program shown in the following lines:

Subscriber 'subscriber-A' just subscribed to OnNameChanged. Subscriber 'subscriber-B' just subscribed to OnNameChanged. Subscriber 'subscriber-C' just subscribed to OnNameChanged. [subscriber-A] Customer firstname changed to Kevin. [subscriber-B] Customer firstname changed to Kevin. [subscriber-C] Customer firstname changed to Kevin. [subscriber-A] Customer lastname changed to Hoffman. [subscriber-B] Customer lastname changed to Hoffman. [subscriber-C] Customer lastname changed to Hoffman. Subscriber 'subscriber-B' just un-subscribed from OnNameChanged. [subscriber-A] Customer firstname changed to Joe. [subscriber-C] Customer firstname changed to Joe. [subscriber-A] Customer middlename changed to Scott. 

As you can see from this output, all three subscribers subscribe to the OnNameChanged event. All three of them receive a notification indicating that the first name and last name changed. Then, after subscriber B unsubscribes, only subscribers A and C receive the notification that the first name was changed. Finally, only subscriber A receives notification that the middle name changed because subscriber C was specifically prevented from receiving the event.

Microsoft Visual C# 2005 Unleashed
Microsoft Visual C# 2005 Unleashed
ISBN: 0672327767
EAN: 2147483647
Year: 2004
Pages: 298 © 2008-2017.
If you may any questions please contact us: