Learning events and Delegation

Source: Internet
Author: User
Tags class manager

Simple introduction to events and Delegation

Blog garden-sun wutian Co., http://www.cnblogs.com/edgar-sun/archive/2007/04/08/704335.html.

Address: http://www.codeproject.com/csharp/events.asp
Download source code:/Files/edgar-sun/events_src.zip
Demo File Download:/Files/edgar-sun/events_demo.zip
Author: Maysam Mahfouzi
Original article released on: 2003/8/16
Original article updated on: 2005/5/14

Content

Introduction
What is delegation?
Understanding events
Event keyword
End

 

Introduction
When I tried to learn about events and Delegation, I read many articles to fully understand and use them. Now I want to show what I learned here, there is a lot of knowledge you need to learn.
What is delegation?
Delegation and events are closely linked. A delegate is a function (method) pointer. More specifically, a delegate maintains reference to a method.
A delegate is a class. When you create an instance, you pass the name of the method that will be called by the delegate (as a parameter of the Delegate constructor ).
Each delegate has a feature. For example:

Delegate int SomeDelegate (string s, bool B );

Is a delegate statement. I have said that it has a feature because it returns an int type value with two parameters, the type is
String and bool.
As I said, When you instantiate a delegate, you pass the name of the method called by the delegate as its constructor parameter. It is important that only methods with the same features as the delegate can be used as their parameters.
Take a look at the following method:

Private int SomeFunction (string str, bool bln ){}
You can pass this method to the SomeDelegate constructor as parameters because they have similar features.
SomeDelegate sd = new SomeDelegate (SomeFunction); now sd references SomeFunction, in other words, SomeFunction is registered to sd. If you call sd, SomeFunction will also be called. Remember the meaning of the registered method. We will reference it later.
Sd ("somestring", true );
Now that you know how to use the delegate, let's understand the event ......

Understanding events
A button is a class. When you click it, the click event is triggered.
A timer is a class that triggers a tick event every millisecond.
Want to know what happened? Let's use an example to learn:
This is a assumption: We have a Counter class. This class has a councounter (int counTo, int reachableNum) method, which starts from 0 to count, and triggers a NumberReached event as long as it counts to the number of reachableNum.
Our class has an event: NumberReached. Events are delegate variables. I mean, if you declare an event, declare a type of delegate, and put the event keyword before the declaration, it looks like this:

Public event NumberReachedEventHandler NumberReached;
In the preceding statement, NumberReachedEventHandler is only a delegate. Maybe it should be called NumberReachedDelegate, but it is noted that Microsoft is not called MouseDelegate or PaintDelegate, but MouseEventHandler or PaintEventHandler. Name it NumberReachedEventHandler instead of NumberReachedDelegate. This is just a convention, understand? Good!
Before declaring an event, you need to define the corresponding delegate (event handler ). It may look like this:

Public delegate void NumberReachedEventHandler (object sender,
NumberReachedEventArgs e );
As you can see, the delegate name is NumberReachedEventHandler, which returns a void value. The two parameter types are object and NumberReachedEventArgs. If you instantiate this delegate somewhere, the method you pass must have the same features as it.
In your code, have you used MouseEventArgs or PaintEventArgs to determine the location of the mouse, where it moves, or the graphic attribute of an object to trigger the Paint event? In fact, we provide our data to users in the classes inherited from the EventArgs class. For example, in our example, we provide the reachable number. The declaration of this class is as follows:

Public class NumberReachedEventArgs: EventArgs
{
Private int _ reached;
Public NumberReachedEventArgs (int num)
{
This. _ reached = num;
}
Public int ReachedNumber
{
Get
{
Return _ reached;
}
}
}
If you do not need to provide any information to the user, you can directly use the EventArgs class.
Now, everything is ready. Let's take a look at the internal implementation of the Counter class:

Namespace Events
{
Public delegate void NumberReachedEventHandler (object sender,
NumberReachedEventArgs e );

/// <Summary>
/// Summary description for Counter.
/// </Summary>
Public class Counter
{
Public event NumberReachedEventHandler NumberReached;

Public Counter ()
{
//
// TODO: Add constructor logic here
//
}
Public void countid (int countid, int reachableNum)
{
If (countings <reachableNum)
Throw new ArgumentException (
"ReachableNum shocould be less than countid ");
For (int ctr = 0; ctr <= countid; ctr ++)
{
If (ctr = reachableNum)
{
NumberReachedEventArgs e = new NumberReachedEventArgs (
ReachableNum );
OnNumberReached (e );
Return; // don't count any more
}
}
}

Protected virtual void OnNumberReached (NumberReachedEventArgs e)
{
If (NumberReached! = Null)
{
NumberReached (this, e); // Raise the event
}
}
}
In the above Code, an event is triggered when the expected number is reached. Here we need to consider many things:
1. An event is triggered by calling an instance of NumberReachedEventHandler.

NumberReached (this, e );
In this way, all registered methods will be called.
2. Run the following code for the registered method data:

NumberReachedEventArgs e = new NumberReachedEventArgs (reachableNum );
3. One question: why do we indirectly call the NumberReached (this, e) event through the OnNumberReached (NumberReachedEventArgs e) method? Why don't we use the following code:

If (ctr = reachableNum)
{
NumberReachedEventArgs e = new NumberReachedEventArgs (reachableNum );
// OnNumberReached (e );
If (NumberReached! = Null)
{
NumberReached (this, e); // Raise the event
}
Return; // don't count any more
}
Good question! For more information about indirect calls, see the features of the OnNumberReached method:

Protected virtual void OnNumberReached (NumberReachedEventArgs e)
As you can see, it is a protection method, which means that it can be called from the class (subclass) inherited by this class.
It is also a virtual method, which means that sub-classes can rewrite its implementation.
It is very useful. Imagine you are designing a class inherited from the Counter class. By Rewriting the OnNumberReached method, you can easily add additional work before the event is triggered. For example:

Protected override void OnNumberReached (NumberReachedEventArgs e)
{
// Do additional work
Base. OnNumberReached (e );
}
Note that if you do not call base. OnNumberReached (e), the event will never be triggered. When you inherit some classes, you may want to remove some events. This may be useful. Interesting tips, huh?
A real example, when you create a new ASP.. NET application, you can view the code generated in the background, and you will find that your page inherits from System. web. UI. page class, and there is a protection virtual method called OnInit. Here, an InitializeComponent () method is called to do some additional work, and then the OnInit (e) method of the base class is called:

# Region Web Form Designer generated code
Protected override void OnInit (EventArgs e)
{
// CODEGEN: This call is required by the ASP. NET Web Form Designer.
InitializeComponent ();
Base. OnInit (e );
}
/// <Summary>
/// Required method for Designer support-do not modify
/// The contents of this method with the code editor.
/// </Summary>
Private void InitializeComponent ()
{
This. Load + = new System. EventHandler (this. Page_Load );
}
# Endregion
4. Pay attention to the NumberReachedEventHandler delegate, which is defined outside the Counter class and within the Events namespace and is visible to all classes.
Well, it's time to practice our Counter class.
In our application, we have two text boxes: txtcountings and txtReachable.

Here is the btnRun button click event processing code:

Private void cmdRun_Click (object sender, System. EventArgs e)
{
If (txtcountings. Text = "" | txtReachable. Text = "")
Return;
OCounter = new Counter ();
OCounter. NumberReached + = new NumberReachedEventHandler (
OCounter_NumberReached );
OCounter. Counter (Convert. ToInt32 (txtcounw.text ),
Convert. ToInt32 (txtReachable. Text ));
}

Private void oCounter_NumberReached (object sender, NumberReachedEventArgs e)
{
MessageBox. Show ("Reached:" + e. ReachedNumber. ToString ());
}
Here is the syntax for initializing event delegation for an event:

OCounter. NumberReached + = new NumberReachedEventHandler (
OCounter_NumberReached );
Now you should know what we are doing. We initialized the NunberReachedEvnetHandler delegate (or other objects ). Note the similarity of the oCounter_NumberReached method signature I mentioned above.
Now let's take a look at the situation where we use = instead of + =.
A delegate is a special object, because it can maintain the reference of multiple objects (here there are multiple methods ). For example, if you have another method named oCounter_NumberReached2 and the signature is the same as oCounter_NumberReached, both methods can be referenced as follows:

OCounter. NumberReached + = new NumberReachedEventHandler (
OCounter_NumberReached );
OCounter. NumberReached + = new NumberReachedEventHandler (
OCounter_NumberReached2 );
Now, when an event is triggered, one method after another is called.
If you do not want to call oCounter_NumberReached2 when the NumberReached event is triggered somewhere in your code, you can do this:

OCounter. NumberReached-= new NumberReachedEventHandler (
OCounter_NumberReached2 );
Event keyword
Many may ask: what if we don't need the event keyword?
The evnet keyword can be used to prevent any delegate user from setting it to null. Why is this important? Imagine that a customer registers one of the methods in my class to the delegate call linked list, and other customers do the same. This will not cause errors. Now, if another customer uses = instead of + = to delegate a new registration method. This will clear the original delegate call linked list and create a new single delegate in the delegate call linked list. At this time, other customers will not be able to receive replies. The keyword event is designed to address this issue. If I add the event keyword in the Counter class and try to compile the following code, a compiler error message will be generated:

In short, the event keyword adds a protection layer to the delegated instance to protect the client from re-setting and emptying the delegated call chain, in this way, only the delegate call chain can be added or removed.
End
Don't forget to declare the following content in your application's constructor, instead of in the cmdRun_Click event processing code. I did that just for simplicity .; -)

Public Form1 ()
{
//
// Required for Windows Form Designer support
//
InitializeComponent ();

//
// TODO: Add any constructor code after InitializeComponent call
//
OCounter = new Counter ();
OCounter. NumberReached + = new NumberReachedEventHandler (
OCounter_NumberReached );
OCounter. NumberReached + = new NumberReachedEventHandler (
OCounter_NumberReached2 );
The source code provided is like this.

This article from the CSDN blog, reproduced please indicate the source: http://blog.csdn.net/xychen2008/archive/2007/04/26/1585238.aspx

 

 

C # delegation mechanism application example

Events and delegation seem to be hard to understand, because their usage is very different from common encodings. For example, we usually write Synchronous Code and call a type of method, the result of method execution is displayed immediately, which is logical. However, in some cases, the Synchronous Code may not meet the requirements. Take the bus for example, if the Traffic Control Center wants each bus to send a signal to itself when arriving at a site so that they can know the traffic conditions at any time, and use the Synchronous Code, the public steam object must certainly call the control center object, in this case, two types are closely coupled. Since other types need to respond to their own behaviors, it seems inevitable to call methods of their types in person. In synchronous code, it is difficult to avoid this close type call relationship.

The other difference is that in general, we only pass attributes as parameters to methods, but seldom consider passing one method to another method.

We discard the difficult concepts of events and delegation in various C # reference books, and imagine a scenario to understand the use of events and delegation: an IT company, the chairman does not want his employees to play games during work hours, but may not stare at every employee all the time. Therefore, he wants to use a new method to monitor employees: if an employee violates regulations, a device or a specialized invigilator will automatically send a message to him, and the chairman of the board only needs to handle the incident.

Therefore, this use case is actually an interaction between the Chairman and employee. The following code shows you how to use the delegate and event mechanism to implement this interaction:

First, we need to define a delegate type between the chairman class and the employee class to transfer events between the two. This type is a monitoring device or an invigilator responsible for reporting small reports:

Public delegate void DelegateClassHandle ();

The process of defining a delegate is similar to the definition of a method, but it does not have a method body. To define a delegate, you must add the keyword delegate. Since the definition delegate is actually quite a class, you can define the delegate anywhere in the definition class. In addition, you can add general access modifiers such as public, private, and protected based on the delegate visibility.

The Return Value Type of a delegate is void, which does not indicate that the delegate type has a return value. The return value type refers to the target function type of the delegate, that is, the return value of an event processing function entrusted by the delegate is void.

The code for creating an Employee class is as follows:

Public class Employee
{
Public event DelegateClassHandle PlayGame;
 
Public void Games ()
{
If (PlayGame! = Null)
{
PlayGame ();
}
}
}
The Employee class Employee code defines a DelegateClassHandle-type event PlayGame, which is also defined in a special way. First, you must use the keyword event to indicate that PlayGame is an event, at the same time, you must declare that the delegate type of this event is DelegateClassHandle. The delegate object of this type will be responsible for notifying the event.
If an employee starts playing a game, it will execute the Games method. Once this method is called, an event PlayGame will be triggered, then the Chairman will receive a message about the event-someone is playing a game.
The Chairman class code is as follows. He has a method named Notify y to receive messages:
Public class Admin
{
Public void Policy ()
{
System. Console. WriteLine ("someone is playing game ");
}
}
How can I associate the PlayGame event of Employee ee with the Notify method of Admin? You only need to bind events. The specific process is as follows:
Employee employee = new Employee ();
Admin admin = new Admin ();
 
Employee. PlayGame + = new DelegateClassHandle (admin. Policy );
Employee. Games ();
Pay attention to the code bound to the event:
Employee. PlayGame + = new DelegateClassHandle (admin. Policy );
Use DelegateClassHandle to bind the interaction between the two classes. after the Games method is called, the PlayGame event is triggered, and the event will be delegated to the Notify method of admin for handling, notifying the chairman of the board of directors that an employee plays the game during work hours.
However, the chairman of the board is not satisfied with this simple notification. He also wants to know who violates the regulations during work hours. Obviously, the required parameters must be passed to the delegate object, which can be easily implemented. The event parameters can be set to any type of data. In the. NET Framework, the event parameter base class EventArgs is also provided for passing event data.
A Custom Event parameter class CustomeEventArgs is derived from the EventArgs class, which carries the employee name and age information:
Public class CustomeEvetnArgs: EventArgs
{
String name = "";
Int age = 0;
Public CustomeEvetnArgs ()
{}
Public string Name
{
Get {return this. name ;}
Set {this. name = value ;}
}
Public int Age
{
Get {return this. age ;}
Set {this. age = value ;}
}
}
Modify the definition of the delegate type DelegateClassHandle to include the necessary parameters:
Public delegate void DelegateClassHandle (object sender, CustomeEvetnArgs e );
The employee class code is modified as follows:
Public class Employee
{
Private string _ name;
 
Public string Name
{
Get {return _ name ;}
Set {_ name = value ;}
}
Private int _ age;
 
Public int Age
{
Get {return _ age ;}
Set {_ age = value ;}
}
 
Public event DelegateClassHandle PlayGame;
 
Public void Games ()
{
If (PlayGame! = Null)
{
CustomeEvetnArgs e = new CustomeEvetnArgs ();
E. Name = this. _ name;
E. Age = this. _ age;
PlayGame (this, e );
}
}
}
In the Games method, create a CustomeEventArgs object, and set the required attributes Name and Age.
The Chairman's notice method must also be modified accordingly:
Public class Admin
{
Public void Policy (object sender, CustomeEvetnArgs e)
{
System. Console. WriteLine (e. Name + "is" + e. Age. ToString ());
}
}
The code for associating two types of objects also needs to be modified accordingly:
Employee employee = new Employee ();
Employee. Name = "Mike ";
Employee. Age = 25;
Admin admin = new Admin ();
 
Employee. PlayGame + = new DelegateClassHandle (admin. Policy );
Employee. Games ();
After the modified Code is run, when Mike calls the Games method to play the game, the PlayGame event is automatically triggered, and the event carries the relevant information to notify admin, the latter's Notify y method will receive the data and output "Mike is 25", telling the Chairman that Mike is 25 years old and is playing games during work hours.
 
A delegate can be a multi-channel broadcast (Mulitcast), that is, an event can be delegated to multiple objects for receiving and processing. In the preceding example, if another manager has the same preferences as the chairman of the board, the delegate can notify the employee of the PlayGame event.
First, define the manager class:
Public class Manager
{
Public void Policy (object sender, CustomeEvetnArgs e)
{
System. Console. WriteLine (sender. ToString () + "-" + e. Name );
}
}
The Notify method of the Manager type is the same as that of the Admin type, and the corresponding information is also received.
The bind method of the delegate multicast is still using the + = Operator. The method is shown in the following code:
Employee employee = new Employee ();
Employee. Name = "Mike ";
Employee. Age = 25;
Admin admin = new Admin ();
Manager manager = new Manager ();
 
Employee. PlayGame + = new DelegateClassHandle (admin. Policy );
Employee. PlayGame + = new DelegateClassHandle (manager. Policy );
Employee. Games ();
When this method is executed, the reader will see that the Notify y method of admin and manager will be notified and called for execution. In this way, both the Chairman and manager will know that Mike is playing the game.

If the Chairman does not want the manager to receive this notification, how can he unbind PlayGame from the manager event? It is also very simple. Run the following statement before the employee. Games method is called:

Employee. PlayGame-= new DelegateClassHandle (manager. Policy );

Finally, we should remind readers that the Games method in the Employee class should determine whether the event is null before triggering the event PlayGame. When the Games method of the employee object triggers the event PlayGame, a target function must be provided to handle the event, and the statement determines whether the target function exists. If the game method is called directly without binding the event, an NullReferenceException occurs in the event PlayGame.

Can the reader draw any conclusions from the delegate and Event code? There are two types that need to have a call relationship, but no actual call code is written in their respective implementations. They only complete the message transmission process through an event and a third-party delegate type. There is no close coupling between the two types. They seem to communicate loose through a delegate object, realizing the "high aggregation" and "low coupling" ideas that have been promoted in this book.

 

This article from the CSDN blog, reproduced please indicate the source: http://blog.csdn.net/yap111/archive/2008/02/20/2110544.aspx

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.