Asynchronous Processing without Threads
This section is short because you probably already know how to use a timer. Visual Basic .NET supports an Application object, similar to the VB6 App object. The VB .NET Application object implements an Idle event. You can assign a delegate to the Application.Idle event and achieve asynchronous capabilities too.
Using a Timer
The Timer is implemented as a control. A crystal oscillates at a certain frequency in your PC and this known oscillating frequency is used to clock your PC. At a very low level, the BIOS supports implementing an interrupt event handler that is notified when the internal hardware timer ticks . After 10 years or so, the low-level capabilities inherent in the average PC were wrapped in a control.
The Timer control supports your indicating a number of milliseconds to wait before the timer raises an event. When the indicated milliseconds elapse, the Timer control raises a Tick event in VB .NET.
A common task for which the timer is used is to display a clock on the status bar. The following code fragment demonstrates what this might look like in .NET:
Private Sub Timer1_Tick(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Timer1.Tick StatusBar1.Text = Now End Sub
The fragment assumes that you have a Windows Form with a Timer control added to the component tray, and perhaps you clicked the control to generate the event handler.
The timer tick operates asynchronously, but the event is still on the same thread as the form. This means that it is safe to interact directly with Windows Forms controls in a timer event handler, but you do not want the timer to fire a second time while you are still processing a previous request.
Asynchronous timer tasks should be concise . A reasonable amount of work is similar to that performed when updating a viewable clock. Much more than that, and you should consider using a different approach.
Using the Application Idle Event
Applications spend a significant amount of time idle. Just look in Windows Task Manager and you can see that processor utilization peaks occasionally, but most processes sit around waiting most of the time. Visual Basic .NET supports adding an event handler to respond to the application idle event.
Currently, Application is not represented as a control. You just have to know it is there. The Application class is defined in System.Windows.Forms, making it available to Windows applications but not console or Web applications.
To use the Idle event, you will need to define a method in your application, preferably the main form that is always open, and use AddHandler to associate the method-as-delegate to the Idle event. Listing 14.1 demonstrates very brief code that does exactly this.
Listing 14.1 Assigning an event handler to the Application.Idle event
1: Public Class Form1 2: Inherits System.Windows.Forms.Form 3: 4: [ Windows Form Designer generated code ] 5: 6: Private Sub OnIdle(ByVal sender As Object, ByVal e As EventArgs) 7: Text = Now 8: End Sub 9: 10: Private Sub Form1_Load(ByVal sender As System.Object, _ 11: ByVal e As System.EventArgs) Handles MyBase.Load 12: 13: AddHandler Application.Idle, AddressOf OnIdle 14: 15: End Sub 16: End Class
The Idle event property is defined as an EventHandler delegate. From Chapters 8 and 9, you know that EventHandler is initialized with the address of a subroutine that has Object and EventArgs parameters, as does OnIdle defined on lines 6 through 8. The Application.Idle event is associated with the OnIdle method in the form's Load event.
Line 13 effectively associates an event handler with an event (in the preceding example, the Idle event). What the AddressOf actually does is construct an instance of a delegate. The statement on line 13 is identical to AddHandler Application.Idle, New EventHandler(AddressOf OnIdle).
Examining the verbose form of the call, it is clear that EventHandler is a class. In fact, it's a delegate class. It is also clear that we are initializing the class with the address of a procedure, a function pointer.
Personally I think it would be clearer to write Application.Idle = AddressOf OnIdle. When I asked some folks at Microsoft why it wasn't implemented using assignment, the response I got had to do with overloading the assignment (=) operator to work with delegate objects. Regardless, it is worth noting that AddressOf implicitly constructs a delegate object, and .NET supports the verbose form of delegate construction, which you are likely to encounter.
The code updates the time as the form's caption but does so at irregular intervals. The Timer is better for a clock. Like the Timer control, the Application.Idle event is suitable for short processes. Unlike the Timer control, Application.Idle is more suited for tasks that can run at irregular intervals; if they don't run, they will not have a deleterious impact on your application.
The Timer control and the Application object are useful, but that's not why we're here. One final word on these two ways of performing asynchronous processes: They are easy to use and less likely to introduce bugs , so don't completely overlook them. Now on to meatier subjects.