Framework class library event programming
Release Date: 1/24/2005
| Update Date: 1/24/2005
TED Pattison
This page
EventHandler delegate custom event parameter parameterization custom event summary
The content of this month is the last phase of the series of columns (a total of three issues) specifically introduced. In the previous two columns, I have already introduced how to define and trigger events (see Basic Instincts: Programming With events for .NET and Basic Instincts: Static Event Binding Using Withevents). I also explain how to use dynamic and static event bindings to bind the event handler. This month, I will summarize the introduction of the event by some of the more common event handling instances in Microsoft .NET Framework.
EventHandler commission
When you use a Windows® form or ASP.NET to build an application, you will see that a considerable ratio in the event encountered is defined according to a general commission type named EventHandler. The EventHandler type is existing in the System namespace and has the following definition:
Delegate Sub EventHandler (Sender As Object, E AS Eventargs)
The delegate type EventHandler defines two parameters in its call signature. The first parameter (named Sender) is based on a general purpose Object type. The Sender parameter is used to pass references to the active source object. For example, when the Button object raises an event based on an EventHandler delegate type, it will pass a reference to its own reference.
The second parameter defined by EventHandler is called E, which is an object of EventArgs. In many cases, the parameter value passed by the event source is equal to Eventargs.empty, which indicates that there is no additional parameter information. If the event source wants to pass additional parameterized information in the E parameter, it should pass an object created from the Eventargs class.
The example shown in Figure 1 contains two event handlers in the Windows Form application that binds with static event bindings. The FORM class's LOAD event and the Button class CLICK event are defined according to the principal EventHandler.
You should also note that the names and formats of the two event handler methods in Figure 1 are consistent with Visual Studio .NET IDE. For example, if you double-click a form or a command button in the design view, Visual Studio .NET will automatically create a similar event handler method. You need to do just fill the implementation of these methods in order to give your event handler to expected behavior.
You may notice that Visual Studio .NET IDE is a naming scheme that uses Visual Basic 6.0 to generate a processor method. However, you should remember that static event binding in Visual Basic .NET does not really do with the name of the handler method. It is associated with the Handles clause. You can randably rename the handler method as any name you need.
You can rewrite these two event handles so that they can be bound to dynamic event bindings (rather than static event bindings). For example, the class derived from the FORM is provided from the Form derived from the form, which is identical to event binding behavior as the class derived from the Form. The only difference is that the latter uses dynamic event bindings and does not require a WitHevents keyword or a handles keyword. In many cases, you will write the implementation of the handler method according to the EventHandler entrustment type, not the reference sender parameter or E parameter. For example, these parameter values do not actually work when you write a handler for the LOAD event derived from the Form. Sender does not provide any value because it only passes the ME reference. E parameter delivery Eventargs.empty: Sub Form1_Load (Sender As Object, E AS Eventargs) Handles MyBase.Load
'*** these tests area always true
Dim test1 as boolean = sender is me
DIM Test2 as boolean = e is Eventargs.empty
End Sub
You may want to know why the calling signature of the load event is not for more customizations. After all, if the LOAD event does not contain any parameters, the situation will not be so confusing. It is easy to find other events based on EventHandler delegate types (and its Sender parameter or E-parameter do not pass any value).
Please answer the following questions. If the delegate type has such a general call signature, why do you think so many events are modeled according to EventHandler? Why does the .NET Framework designer not based on a custom delegate with a call signature that is suitable for it? As you know, a design goal in .NET Framework development is to limit the number of delegates for event processing. The following is a further explanation.
The first purpose of minimizing the number of entrustments is to use the memory used by the application more effectively. Loading more type means taking up more memory. If each event defined by the class definition in the Windows Forms Framework is based on a custom delegate, you must load the hundreds of delegate types to memory every time you run a Windows Form application. The Windows Forms Frame can rely on rare delegate types to define hundreds of events in the Form class and various control classes, thereby providing better memory utilization.
The second purpose of minimizing the number of entrustments is to increase the possible possible polymorphism using the plug-in handler method. When you use a call signature that is entrusted with the EventHandler to write a handler method, you can bind it to most of the events thrown by the form and its controls.
Let us see some examples of writing general event handles. First introduce this example: In this example, you can respond to the TextChanged event in the form in the form in the form by rewriting user input to uppercase. There is no need to create a separate event handler for each control. Instead, you can only create an event handler, then bind it to the TextChanged event of multiple different text boxes (see Figure 3).
For this example, it should be noted that the Handles clause is not limited to an event. You can use a comma-separated list to include any number of events later in the Handles keyword. In this example, the TextChangeDHandler method is used to create three different event handler. Therefore, this method will be executed when the user changes any of these three text boxes.
How do you know which TEXTBOX object triggered when you execute the TextChangeDHandler method? This is the problem that the Sender parameter should be solved. Keep in mind that the Sender parameter is passed according to General Type Object. This means that it must be converted into a more specific type before programming it. In the previous example, the text property of the Sender parameter is to be accessed, the parameter must be converted to TextBox. If you have generated a form-based application using the earlier versions of Visual Basic, you may be accustomed to using an array of controls. The main advantage of using the control array in Visual Basic 6.0 is that this feature makes it possible to create a handler method that can respond to events caused by multiple different controls. Visual Basic .NET does not support an array of controls. However, you don't have to be too tight, because you have already seen that Visual Basic .NET provides an alternative technology that can bind a handler method to multiple different events.
The Event architecture of the .NET Framework also provides you with the ability to implement an array of controls. For example, you can create a handler method to respond to events caused by multiple different types of controls. Figure 4 shows an example of a handler method that binds to three different events on three different control types.
As you can see, the scheme of the handler method is binding to the event is quite flexible. The only requirement is that the handler method and the event it binds should be based on the same entrustment type. There are quite a few incidents in .NET Framework are based on the EventHandler entrustment type, which makes it easy to write general handler methods.
When you write a generic handler method, you sometimes need to write code to perform conditional operations, and these operations are only performed when the event source is a particular type of object. For example, your handler method can use the TypeOf operator to check the sender parameter. This allows your handler method to perform a set of operations when the event source is the Button object, and performs another set of operations when the event source is Checkbox object, as shown below:
Sub GenericHandler1 (Sender As Object, E AS Eventargs)
IF (TypeOf Sender Is Button)
Dim btn as button = ctype (sender, button)
'*** Program Against BTN
Elseif (Typeof Sender Is Checkbox)
DIM Chk as Checkbox = CType (Sender, Checkbox)
'*** Program Against Chk
END IF
End Sub
Back to top
Custom event parameters
EventHandler-based event notifications are usually not sent to any meaningful information in the E parameter. The E parameter is usually useless because it contains the Eventargs.empty value or the Nothing value. However, .NET Framework's designer created an agreement to pass parameterized information from the event source to its event handler. This agreement includes custom event parameter classes and creation of custom delegate types.
The mouse event caused by the Form class provides a good example of how to use this agreement. The parameterized information about which mouse button is pressed is modeled in a class named MouseEventArgs. The MouseEventArgs class contains the X and Y properties for tracking the mouse location, and the Button property for indicating which mouse button is pressed. Please note that follow the convention, the MouseEventArgs class must inherit from General class Eventargs.
The agreement of passing parameterized information in an event notification requires a custom delegate to supplement the custom event parameter class. Therefore, there is a delegate named MouseEventHandler to supplement the MouseEventArgs class. The definition of this handler is as follows: DELEGATE SUB MOUSEEVENTHANDLER (Sender AS Object, e as mouseeventargs)
Now, suppose you want to respond to a mouse-related event (such as a MouseDown event). You can write a processor method as shown in Figure 5.
Note that the E parameter is very useful in the implementation of the handler method. The E parameter is used to determine the position of the mouse and which mouse button is pressed. All of these parameterized information can be implemented by designing the MouseEventArgs class.
You can find other examples of this parameterization appointed in the Windows Forms Framework. For example, there is a class called KeyPressEventArgs, which is supplemented by a delegate type named KeyPressEventHandler. In addition, the ItemChangeDargs class is supplemented by a delegate type named ItemChangeDHandler. You may encounter its parameterized information and follow this agreed event.
Back to top
Parameterized custom event
As an exercise, let's design a custom event to follow this agreement. I will use an example similar to I use in the recent column, which includes a BankAccount class. Consider the following code snippet:
Class BankAccount
Sub withdraw (ByVal Amount As Decimal)
'*** Send Notifications IF Required
IF (Amount> 5000) THEN
'*** raise Event
END IF
'*** Perform withdrawal
End Sub
END CLASS
Assumptions require the BankAccount object to trigger an event every time the amount of withdrawal amount is greater than $ 5,000. When triggering the event, you are required to pass the amount amount as a parameter to all registered event handler. First, you should create a new event parameter class that inherits from the Eventargs class:
Public Class Largewithdrawargs: inherits Eventargs
Public Amount As Decimal
Sub New (ByVal Amount As Decimal)
Me.amount = Amount
End Sub
END CLASS
Custom Event Parameters should be designed to: For each parameterized value that is passed to its event handler for event sources, it contains a public field. In this example, the LargewithDrawargs class is designed to include a Decimal field called Amount. Next, you must create a new entrustment type to supplement the new event parameter class:
Delegate Sub Largewithdrawhandler (Byval Sender As Object, _
Byval e as largewithdrawargs)
According to the agreement, this delegate type is defined as the Object parameter named Sender as the first parameter. The second parameter E is based on a custom event parameter class.
Now, you have created a custom event parameter class and a supplementary commission, you can put them in use. Please examine the following definition:
Class BankAccount
Public Event Largewithdraw As LargewithDrawhandler
Sub withdraw (ByVal Amount As Decimal)
'*** Send Notifications if Requiredif (Amount> 5000) THEN
Dim Args As New Largewithdrawargs (Amount)
RaiseEvent LargewithDraw (ME, ARGS)
END IF
'*** Perform withdrawal
End Sub
END CLASS
It modifies the LARGEWITHDRAW event, you can use the standards in the .NET Framework to pass parameterized information in the event notification. When triggering a LARGEWITHDRAW event in the WithDraw method, it is necessary to create a new LARGEWITHDRAWARGS class instance and passed it as a parameter. Since the BankAccount object triggers the event, you can use the Me keyword to pass the sender parameters, as shown below:
Dim Args As New Largewithdrawargs (Amount)
RaiseEvent LargewithDraw (ME, ARGS)
Since you have already understood how to create an event source, we will turn your attention to how to create a handler method for this event. The handler method should be able to retrieve the parameterized information it needs via the E parameter. In this example, the handler method will use the E parameter to retrieve the value of the AMOUNT field:
Sub Handler1 (Sender As Object, E AS LARGEWITHDRAWARGS)
'*** Retrieve Parameterized Information
Dim amount as decimal = E.Amount
End Sub
Figure 6 shows a complete application that the BankAccount object will send event notifications when extracting a large amount. Please note that this application is in line with the standard public language runtime aggregation agreement of parameterized information in an event.
Back to top
summary
This section summarizes the basics of event programming using Visual Basic .NET. The first two columns describe the mechanisms that trigger and handle events. This month's column focuses on the general events and delegate programming instances defined in .NET Framework.
Most events processed through Visual Basic .NET are probably based on EventHandler delegate. If you see, you can bind multiple events to a handler method. In this case, it is important to know when and how to use the Sender parameters. You also have learned that some other events that use custom parameter classes pass parameterized information. In summary, you should now use event-driven frameworks (such as Windows Forms or ASP.NET) to make some development work.
Please send TED questions and comments to instinct@microsoft.com.
Ted Pattison is a teacher and course author of developor (http://www.develop.com). He has written a few books about Visual Basic and COM, and he is currently writing a book named Building Applications and Components with Visual Basic .NET (Addison-Wesley, 2003).