65.9K
CodeProject 正在变化。 阅读更多。
Home

WinForms 的应用程序事件处理程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (15投票s)

2004年11月12日

6分钟阅读

viewsIcon

158872

downloadIcon

1883

在本文中,您将学习如何在 .NET 中为任何 WinForms 应用程序创建一个应用程序事件处理程序组件 (AEHC)。

Screenshot

目录

引言

在本文中,您将学习如何在 .NET 中为任何 WinForms 应用程序创建一个应用程序事件处理程序组件 (AEHC)。AEH 是您 WinForms 应用程序的事件处理程序。该组件的主要功能是在每个窗体加载到内存后引发一个事件,以便我们可以处理其事件以执行任何自定义代码处理,并在处理后将控件返回给窗体。

让我们考虑一个场景。在为应用程序实现安全性时,我们可能需要根据访问表单的用户角色来禁用或启用每个表单上的某些控件。为此,我们将调用一个自定义方法(例如,AuthorizeMe()),以从应用程序的每个表单中执行自定义身份验证和授权。假设,在任何情况下,我们都忘记从某个表单中调用其方法,结果将是该表单没有应用安全性。

现在,有了 AEHC,我们只需在应用程序中从 AEHC 调用一次 AuthorizeMe() 方法,然后 AEHC 将负责在每次窗体加载后执行 AuthorizeMe()

什么是应用程序事件处理程序组件?

在 ASP.NET 中,我们可以创建自定义 HTTP 模块,以便在全局级别为 Web 应用程序中的每个网页添加自定义处理。使用 HTTP 模块的一个好处是您无需从每个网页调用它们;它们将自动为每个网页执行。在应用程序事件处理程序中,您将实现与 HTTP 模块类似的功能。但是,AEHC 将特定于每个应用程序,而 HTTP 模块可以用于整个计算机。

应用程序事件处理程序组件会在应用程序的整个生命周期中跟踪被加载和卸载的窗体,并在应用程序级别生成 FormLoaded()FormUnloaded() 等事件。就像 HTTP 模块一样,您也可以编写自己的模块来在这些事件中操作窗体的属性(参见图 1)。

Application Event Handler Component Lifecycle

图 1 应用程序事件处理程序组件生命周期

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

应用程序事件处理程序组件的架构

应用程序事件处理程序组件建立在 WinForms 发布的窗口消息之上。AEHC 的核心部分是一个 FormFilter,它是一个通过实现 IMessageFilter 创建的自定义消息过滤器类。

让我们深入了解细节,看看应用程序事件处理程序组件是如何工作的(参见图 2)。当您加载 WinForms 应用程序时,它会为其大多数事件生成消息。您可以使用自定义消息过滤器来过滤消息队列。

让我们创建一个 Forms Collection 来保存应用程序中加载的所有窗体。获取应用程序中的活动窗体。检查该窗体是否存在于 Forms Collection 中,如果不存在则将其添加到集合中。

现在向 Form Closed 事件添加一个处理程序,您将使用它在窗体接收到 Close 事件后将其从集合中删除。然后,引发 FormLoaded() 以将控件传递给用户。用户可以处理该事件并执行一些自定义处理,例如自定义身份验证、在加载的窗体中添加新控件,更改窗体的外观。

Workflow of Application Event Handler Component

图 2 应用程序事件处理程序组件的工作流程

创建应用程序事件处理程序组件

应用程序事件处理程序由两个类组成:

  1. FormMessageFilter 类:此类负责过滤由窗体或控件分派的消息。它实现 IMessageFilter 以设计自定义消息过滤器(IMessageFilter 接口用于在消息分派给窗体或控件之前捕获消息)。

    声明两个事件 FormFound()FormUnload() 和一个 ArrayList 来存储 Forms 集合。

    IMessageFilterPreFilterMessage 方法中,将消息的 Msg 属性与消息代码(参见表 1)进行比较,并捕获事件。返回 False 以分派消息,反之亦然。

    MSG 属性与 &HF 进行比较以过滤窗口绘制消息。查找 Form.ActiveForm 属性以识别窗体,并将 Form 添加到 Forms Collection 中。向窗体附加一个事件处理程序,以便在窗体关闭后将其从集合中删除。

    Message 代码 目的
    WM_PAINT 0x000F 当系统或其他应用程序请求绘制应用程序窗口的某一部分时发送
    WM_KEYDOWN 0x0100 当按下非系统键时,发布给具有键盘焦点的窗口
    WM_KEYUP 0x0101 当释放非系统键时,发布给具有键盘焦点的窗口
    WM_MOUSEMOVE 0x0200 当光标移动时发布到窗口
    WM_LBUTTONDOWN 0x0201 当用户在窗口客户区内按下鼠标左键时发布
    WM_LBUTTONUP 0x0202 当用户在窗口客户区内释放鼠标左键时发布
    WM_LBUTTONDBLCLK 0x0203 当用户在窗口客户区内双击鼠标左键时发布
    WM_RBUTTONDOWN 0x0204 当用户在窗口客户区内按下鼠标右键时发布
    WM_RBUTTONUP 0x0205 当用户在窗口客户区内释放鼠标左键时发布
    WM_RBUTTONDBLCLK 0x0206 当用户在窗口客户区内双击鼠标右键时发布
    注意:有关更多消息代码,请参阅 *WINUSER.H*

    表 1:用于自定义过滤器类的消息代码

    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
  2. 应用程序事件处理程序:将 FormMessageFilter 添加到应用程序的消息泵中,以过滤掉窗体绘制消息。以及一个共享的只读 FormsCollection 属性,用于在运行时访问窗体集合。
    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

    您已成功创建了应用程序事件处理程序组件。

使用应用程序事件处理程序组件

现在一切都说完了,您已经完成了应用程序事件处理程序组件的创建。让我们学习如何在您的 WinForms 项目中使用它。

在 VB.NET 中创建一个新的 WinForms 应用程序。要将 AEHC 与 VB.NET WinForms 应用程序一起使用,您需要添加一个模块并编写一个 Sub main 方法。

添加对 AEHC 的引用,并在模块中使用 WithEvents 实例化它,当您想要捕获 FormLoaded()FormUnloaded() 事件时。

通过调用 Init() 方法初始化实例。Init() 将为应用程序注册 AEHC 并开始监视消息队列。

FormLoaded() 事件中,添加用于向加载的窗体添加 Label 控件的代码;对于 FormUnloaded() 事件,只需添加一个消息框,并使用 AEHC 的 FormsCollection 属性通过 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

运行您的项目,看看您的应用程序事件处理程序组件的魔力。您将在窗体上看到一个带有文本“Application Event Handler Component Magic”的标签。为了进行更多测试,您也可以在窗体上放置一个按钮并创建窗体的新实例,您将获得惊人的功能,例如所有显示的窗体都带有标签控件。

结论

应用程序事件处理程序组件对于 WinForms 开发人员来说非常强大,他们可以广泛地将其用于 WinForms 的 UI 定制以及其他任务。他们还可以利用 FormCollection 属性来操作应用程序中的窗体。

消息过滤器是为您的 WinForms 应用程序中的每个窗体添加自定义处理的最简单方法之一。事实上,通过使用相同的机制,您可以在 WinForms 应用程序中模仿 ASP.NET 的一些更出色的功能。在未来的专栏中,我将进一步探讨在 WinForms 中实现 ASP.NET 功能,例如缓存等。

© . All rights reserved.