Contents
Introduction
In this article, you will get a walkthrough of creating an Application Event Handler Component (AEHC) for any WinForms application in .NET. AEH is an event handler for your WinForms application. The primary functionality of this component is to raise an event after every form loads into memory so that we can handle its event for performing any custom code processing and return the control to the form after processing.
Let�s consider a scenario. While implementing security into our application, we may have to disable or enable certain controls on every form according to the role of the user accessing the form. For this, we will call a custom method [for instance, AuthorizeMe()
] to perform custom authentication and authorization from each and every form in our application. Suppose, if in any case, we forget to call its method from one of our forms, in result, there will be no security applied to that form.
Now, with AEHC, we only call the method AuthorizeMe()
once per application from AEHC, and then it's AEHC�s responsibility to execute AuthorizeMe()
every time after the form is loaded.
What is Application Event Handler Component?
In ASP.NET, we can create custom HTTP Modules for adding custom processing to each and every web page in web applications at a global level. One of the benefits you get using a HTTP Module is that you do not need to call them from each and every web page; they will automatically get executed for each of them. In Application Event Handler, you will achieve a similar functionality of HTTP Modules. However, AEHC will be specific to every application in contrast with HTTP Modules which can be used machine wide.
Application Event Handler Component keeps track of the forms being loaded and unloaded throughout the application�s lifecycle and generates events like FormLoaded()
and FormUnloaded()
at application level. Just like HTTP Modules, you too can write your own modules to manipulate the forms properties in these events (see Figure 1).
Figure 1 Application Event Handler Component Lifecycle
Dim WithEvents myHandler As New AEHC.ApplicationEventHandler
Public frCol As ArrayList
Public Sub main()
myHandler.Init()
Application.Run(New Form1)
End Sub
Private Sub myHandler_FormLoaded(ByRef sender As System.Windows.Forms.Form, _
ByVal e As AEHC.AppEventHandlerArgs) Handles myHandler.FormLoaded
sender.Text = Now.ToLocalTime
End Sub
Private Sub myHandler_FormUnloaded(ByVal e As AEHC.AppEventHandlerArgs) _
Handles myHandler.FormUnloaded
MsgBox(e.FormsCollection.Count & " in memory")
End Sub
Architecture of Application Event Handler Component
Application Event Handler component is built upon window messages released by WinForms. The core part of AEHC is a FormFilter
, which is a custom message filter class created by implementing IMessageFilter
.
Let�s get into the details and see how Application Event Handler component works (see Figure 2). When you load a WinForms application, it generates messages for most of its events. You can filter the message queue by using a custom message filter.
Let�s create a Forms Collection to hold all the forms which are being loaded throughout the application. Get the Active Form in the application. Check if the form exists in the Forms Collection, add the Form in the collection if not.
Now add a handler to Form
Closed
event, which you will use to remove the form from the collection when the form receives its Close
event. Now, raise the FormLoaded()
for passing the control to the user. User can handle the event and perform some custom processing like custom authentication, adding new controls in the loaded form changing the form�s appearance.
Figure 2 Workflow of Application Event Handler Component
Creating an Application Event Handler Component
Application Event Handler is composed of two classes:
FormMessageFilter
Class: This class is responsible for filtering messages being dispatched by a form or control. It implements an IMessageFilter
to design a custom message filter (IMessageFilter
interface is used to capture a message before it gets dispatched to a form or control).
Declare two events FormFound()
, FormUnload()
and an ArrayList
to store the Forms collection.
In PreFilterMessage
method of IMessageFilter
, check the Msg
property of the message with message codes (see Table 1) and trap the events. Return False
to dispatch the message and vice versa.
Compare the MSG
property to &HF
for filtering the window paint messages. Look for the Form.ActiveForm
property to identify the form and add the Form
to the Forms Collection. Attach an event handler to form, for removing it from the collection after it is closed.
Message |
Code |
Purpose |
WM_PAINT |
0x000F |
Sent when the system or another application makes a request to paint a portion of an application's window |
WM_KEYDOWN |
0x0100 |
Posted to the window with the keyboard focus when a non system key is pressed |
WM_KEYUP |
0x0101 |
Posted to the window with the keyboard focus when a non system key is released |
WM_MOUSEMOVE |
0x0200 |
Posted to a window when the cursor moves |
WM_LBUTTONDOWN |
0x0201 |
Posted when the user presses the left mouse button while the cursor is in the client area of a window |
WM_LBUTTONUP |
0x0202 |
Posted when the user releases the left mouse button while the cursor is in the client area of a window |
WM_LBUTTONDBLCLK |
0x0203 |
Posted when the user double-clicks the left mouse button while the cursor is in the client area of a window |
WM_RBUTTONDOWN |
0x0204 |
Posted when the user presses the right mouse button while the cursor is in the client area of a window |
WM_RBUTTONUP |
0x0205 |
Posted when the user releases the left mouse button while the cursor is in the client area of a window |
WM_RBUTTONDBLCLK |
0x0206 |
Posted when the user double-clicks the right mouse button while the cursor is in the client area of a window |
Note: See WINUSER.H for more message codes |
Table 1: Message Codes for using in the Custom Filter Class
Friend Shared frmCollection As New ArrayList
Public Event FormFound(ByRef sender As Form)
Public Event FormUnload()
Public Function PreFilterMessage(ByRef m As _
System.Windows.Forms.Message) As Boolean Implements _
System.Windows.Forms.IMessageFilter.PreFilterMessage
If (m.Msg = &H200) Then
If Not (Form.ActiveForm) Is Nothing Then
Dim curForm As Form = Form.ActiveForm
If Not (Search(curForm, frmCollection)) Then
frmCollection.Add(curForm)
AddHandler curForm.Closed, AddressOf MyForm_Closed
RaiseEvent FormFound(curForm)
End If
End If
End If
Return False
End Function
Private Sub MyForm_Closed(ByVal sender As Object, _
ByVal e As System.EventArgs)
Dim k, j As Integer
For i As Integer = 0 To frmCollection.Count - 1
j = i - k
If j > (frmCollection.Count - 1) Then Exit For
If frmCollection(j).IsDisposed = True Then
frmCollection.Remove(frmCollection(j))
k = k + 1
End If
Next
If Not (sender) Is Nothing Then frmCollection.Remove(sender)
RaiseEvent FormUnload()
End Sub
Private Function Search(ByVal fr As Form, _
ByVal frmArray As ArrayList) As Boolean
Dim fr1 As Form
For Each fr1 In frmArray
If fr.Equals(fr1) Then Return True
Next
Return False
End Function
End Class
- Application Event Handler: adds the
FormMessageFilter
to the application's message pump to filter out the form paint messages. And a shared read only FormsCollection
property to access the collection of forms at runtime. Public Class ApplicationEventHandler
Public Event FormLoaded(ByRef sender As Form)
Public Event FormUnloaded()
Public Shared ReadOnly Property FormsCollection() As ArrayList
Get
Return FormMessageFilter.frmCollection
End Get
End Property
Public Sub Init()
Dim MyFilter As New FormMessageFilter
AddHandler MyFilter.FormFound, AddressOf pFormLoaded
AddHandler MyFilter.FormUnload, AddressOf pFormUnLoaded
Application.AddMessageFilter(MyFilter)
End Sub
Private Sub pFormLoaded(ByRef CurForm As Form)
RaiseEvent FormLoaded(CurForm)
End Sub
Private Sub pFormUnLoaded()
RaiseEvent FormUnloaded()
End Sub
End Class
You have successfully created the Application Event Handler component.
Using Application Event Handler Component
Now all said and done, you have finished creating the Application Event Handler Component. Let�s learn to use the same, in your WinForms project.
Create a new WinForms application in VB.NET. To use AEHC with VB.NET WinForms application, you will need to add a module and code a Sub main
method.
Add a reference to AEHC, and instantiate in the module using WithEvents
, when you want to trap the FormLoaded()
and FormUnloaded()
events.
Initialize the instance by calling Init()
method. Init()
will register AEHC for the application and starts monitoring the message queue.
In the FormLoaded()
event, add code for adding a Label
control to the loaded form, and for FormUnloaded()
event, just add a message box and use the FormsCollection
property of the AEHC to get the number of loaded forms by myHandler.FormsCollection.Count
.
Dim WithEvents myHandler As New AEHC.ApplicationEventHandler
Public Sub main()
�Initialize the component
myHandler.Init()
Application.Run(New Form1)
End Sub
Private Sub myHandler_FormLoaded(ByRef sender As _
System.Windows.Forms.Form) Handles myHandler.FormLoaded
Dim label1 As System.Windows.Forms.Label
label1 = New System.Windows.Forms.Label
sender.SuspendLayout()
label1.Font = New System.Drawing.Font("Arial", 14.25!, _
System.Drawing.FontStyle.Bold, _
System.Drawing.GraphicsUnit.Point, CType(0, Byte))
label1.Location = New System.Drawing.Point(8, 8)
label1.Name = "Label1"
label1.Size = New System.Drawing.Size(208, 23)
label1.TabIndex = 0
label1.Text = " Application Event Handler Component Magic "
sender.Controls.Add(label1)
sender.ResumeLayout(False)
End Sub
Private Sub myHandler_FormUnloaded() Handles myHandler.FormUnloaded
MsgBox(myHandler.FormsCollection.Count)
End Sub
Run your project to see the magic of your Application Event Handler Component. You will see a label with text �Application Event Handler Component Magic� on your form. To do more testing, you can also place a button on the form and create new instances of the form; you will get amazing functionality like all the forms being displayed with the label control.
Conclusion
Application Event Handler Component is remarkably very powerful for WinForms developers, which they can extensively use in UI Customization of WinForms, along with other tasks. They can make use of the FormCollection
property too, for manipulating forms in their application.
Message Filters are one of the easiest ways to add custom processing for each Form in your WinForms application. In fact, you can imitate some more good features of ASP.NET in your WinForms apps by using the same mechanism. In future columns, I'll explore more on implementing ASP.NET's features in WinForms, like Caching, etc.