Application Event Handler for WinForms






4.77/5 (15 votes)
Nov 12, 2004
6 min read

158036

1883
In this article, you will get a walkthrough of creating an Application Event Handler Component (AEHC) for any WinForms application in .NET.
Contents
- Introduction
- What is Application Event Handler Component?
- Architecture of Application Event Handler Component
- Creating an Application Event Handler Component
- Using Application Event Handler Component
- Conclusion
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()
'Attaches the Form Filter to the Application
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 anIMessageFilter
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 anArrayList
to store the Forms collection.In
PreFilterMessage
method ofIMessageFilter
, check theMsg
property of the message with message codes (see Table 1) and trap the events. ReturnFalse
to dispatch the message and vice versa.Compare the
MSG
property to&HF
for filtering the window paint messages. Look for theForm.ActiveForm
property to identify the form and add theForm
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() 'Method for filtering the message Public Function PreFilterMessage(ByRef m As _ System.Windows.Forms.Message) As Boolean Implements _ System.Windows.Forms.IMessageFilter.PreFilterMessage 'Blocks messages related to Window Paint event (WM_PAINT 0x000F) If (m.Msg = &H200) Then If Not (Form.ActiveForm) Is Nothing Then Dim curForm As Form = Form.ActiveForm 'Search the forms in the Forms Collection to prevent 'duplication of forms in the collection If Not (Search(curForm, frmCollection)) Then frmCollection.Add(curForm) AddHandler curForm.Closed, AddressOf MyForm_Closed RaiseEvent FormFound(curForm) End If End If End If 'Must return false to dispatch the Message Return False End Function 'Event Handler for Form Close event Private Sub MyForm_Closed(ByVal sender As Object, _ ByVal e As System.EventArgs) Dim k, j As Integer 'Removes the forms which are disposed '(Form.Dispose) rather being closed(Form.Close) For i As Integer = 0 To frmCollection.Count - 1 j = i - k If j > (frmCollection.Count - 1) Then Exit For 'Checks the IsDisposed Property of the Form 'in the Forms Collection If frmCollection(j).IsDisposed = True Then frmCollection.Remove(frmCollection(j)) k = k + 1 End If Next 'Removes the form which raised the close event If Not (sender) Is Nothing Then frmCollection.Remove(sender) RaiseEvent FormUnload() End Sub 'Search Method searches fr(form) in the forms collection (frmArray) 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 onlyFormsCollection
property to access the collection of forms at runtime.Public Class ApplicationEventHandler Public Event FormLoaded(ByRef sender As Form) Public Event FormUnloaded() 'Use this property to access your loaded forms Public Shared ReadOnly Property FormsCollection() As ArrayList Get Return FormMessageFilter.frmCollection End Get End Property 'Attaches FormFilter to the application Public Sub Init() Dim MyFilter As New FormMessageFilter AddHandler MyFilter.FormFound, AddressOf pFormLoaded AddHandler MyFilter.FormUnload, AddressOf pFormUnLoaded Application.AddMessageFilter(MyFilter) End Sub 'Called when any form is loaded in the application Private Sub pFormLoaded(ByRef CurForm As Form) RaiseEvent FormLoaded(CurForm) End Sub 'Called when any form is unloaded in the application 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()
'Initialize the Label
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.