向项目中的所有表单添加事件

mva*_*anu 3 vb.net events ui-automation winforms

如果我想FormForm标题中显示我项目中每个项目的大小,那么最佳方法是什么?
我不想在每个人手动放置一个事件处理程序Form.
我希望这个过程是自动的.
类似于重载Load()事件,在resize事件上添加处理程序.

Jim*_*imi 5

这是尝试实现问题的自动化解决方案.

问题是:
附加的一个或多个事件处理程序的每个现有FormWinForms项目(或它们的子集),而不进行编辑/修改现有的代码这些类.

一个可能的解决方案来自Automation该类,它提供了检测何时打开新窗口的方法,并在其AutomationEvent设置为WindowPattern模式时将事件报告给其自己的Automation.AddAutomationEventHandler的订户 . 该AutomationElement成员必须设置为AutomationElement.RootElement和成员TreeScope.SubTree.EventId
Scope

Automation,对于每个AutomationElement提出的AutomationEvent,报告:
- Element.Name(对应于Windows标题)
- Process ID
- Window Handle(作为整数值)

这些值足以识别属于当前进程的Window; Window句柄允许识别打开的Form实例,测试Application.OpenForms()集合.

单独挑选表格时,Event Handler可以Event选择新的表格.

通过扩展此概念,可以创建预定义的事件列表和附加这些事件的表单列表.
可能,在需要时将类文件包含在项目中.

作为注释,在这种情况下,某些事件将没有意义,因为Automation当窗口已经显示时报告窗口的打开,因此Load()Shown()事件属于过去.


我用几个事件(Form.Resize()Form.Activate())测试了这个,但是在这里的代码我只是.Resize()为了简单而使用.

这是该过程的图形表示.
启动应用程序时,事件处理程序未附加到.Resize()事件.
这只是因为Boolean字段被设置为False.
单击按钮,该Boolean字段设置为True,启用事件处理程序的注册.
.Resize()被注册的事件,所有Forms Window Title将报告窗口的当前大小.

全球处理程序

测试环境:
Visual Studio 2017 pro 15.7.5
.Net FrameWork 4.7.1

导入的命名空间:
System.Windows.Automation

参考组件:
UIAutomationClient
UIAutomationTypes

MainForm 码:

Imports System.Diagnostics
Imports System.Windows
Imports System.Windows.Automation

Public Class MainForm

    Friend GlobalHandlerEnabled As Boolean = False
    Protected Friend FormsHandler As List(Of Form) = New List(Of Form)
    Protected Friend ResizeHandler As EventHandler

    Public Sub New()

        InitializeComponent()

        ResizeHandler =
                Sub(obj, args)
                    Dim CurrentForm As Form = TryCast(obj, Form)
                    CurrentForm.Text = CurrentForm.Text.Split({" ("}, StringSplitOptions.None)(0) &
                                                               $" ({CurrentForm.Width}, {CurrentForm.Height})"
                End Sub

        Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
            AutomationElement.RootElement,
                TreeScope.Subtree,
                    Sub(UIElm, evt)
                        If Not GlobalHandlerEnabled Then Return
                        Dim element As AutomationElement = TryCast(UIElm, AutomationElement)
                        If element Is Nothing Then Return

                        Dim NativeHandle As IntPtr = CType(element.Current.NativeWindowHandle, IntPtr)
                        Dim ProcessId As Integer = element.Current.ProcessId
                        If ProcessId = Process.GetCurrentProcess().Id Then
                            Dim CurrentForm As Form = Nothing
                            Invoke(New MethodInvoker(
                                Sub()
                                    CurrentForm = Application.OpenForms.
                                           OfType(Of Form)().
                                           FirstOrDefault(Function(f) f.Handle = NativeHandle)
                                End Sub))

                            If CurrentForm IsNot Nothing Then
                                Dim FormName As String = FormsHandler.FirstOrDefault(Function(f) f?.Name = CurrentForm.Name)?.Name
                                If Not String.IsNullOrEmpty(FormName) Then
                                    RemoveHandler CurrentForm.Resize, ResizeHandler
                                    FormsHandler.Remove(FormsHandler.Where(Function(fn) fn.Name = FormName).First())
                                End If
                                Invoke(New MethodInvoker(
                                Sub()
                                    CurrentForm.Text = CurrentForm.Text & $" ({CurrentForm.Width}, {CurrentForm.Height})"
                                End Sub))

                                AddHandler CurrentForm.Resize, ResizeHandler
                                FormsHandler.Add(CurrentForm)
                            End If
                        End If
                    End Sub)
    End Sub


    Private Sub btnOpenForm_Click(sender As Object, e As EventArgs) Handles btnOpenForm.Click
        Form2.Show(Me)
    End Sub

    Private Sub btnEnableHandlers_Click(sender As Object, e As EventArgs) Handles btnEnableHandlers.Click
        GlobalHandlerEnabled = True
        Me.Hide()
        Me.Show()
    End Sub

    Private Sub btnDisableHandlers_Click(sender As Object, e As EventArgs) Handles btnDisableHandlers.Click
        GlobalHandlerEnabled = False
        If FormsHandler IsNot Nothing Then
            For Each Item As Form In FormsHandler
                RemoveHandler Item.Resize, ResizeHandler
                Item = Nothing
            Next
        End If
        FormsHandler = New List(Of Form)
        Me.Text = Me.Text.Split({" ("}, StringSplitOptions.RemoveEmptyEntries)(0)
    End Sub
End Class
Run Code Online (Sandbox Code Playgroud)

注意:
此前代码放在应用程序Starting Form(用于测试)中,但最好Module在需要时包含在Project中,而不触及当前代码.

要使其工作,请添加一个包含a 的新Module(命名Program)Public Sub Main(),并更改Project属性以启动应用程序Sub Main而不是a Form.
删除"使用应用程序框架"上的复选标记,然后从"启动对象"组合中选择"Sub Main".

所有代码都可以通过Sub Main几个修改转移到proc:

Imports System
Imports System.Diagnostics
Imports System.Windows
Imports System.Windows.Forms
Imports System.Windows.Automation

Module Program

    Friend GlobalHandlerEnabled As Boolean = True
    Friend FormsHandler As List(Of Form) = New List(Of Form)
    Friend ResizeHandler As EventHandler

    Public Sub Main()

        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)

        Dim MyMainForm As MainForm = New MainForm()

        ResizeHandler =
                Sub(obj, args)
                    Dim CurrentForm As Form = TryCast(obj, Form)
                    CurrentForm.Text = CurrentForm.Text.Split({" ("}, StringSplitOptions.None)(0) &
                                                               $" ({CurrentForm.Width}, {CurrentForm.Height})"
                End Sub

        Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
            AutomationElement.RootElement,
                TreeScope.Subtree,
                    Sub(UIElm, evt)
                        If Not GlobalHandlerEnabled Then Return
                        Dim element As AutomationElement = TryCast(UIElm, AutomationElement)
                        If element Is Nothing Then Return

                        Dim NativeHandle As IntPtr = CType(element.Current.NativeWindowHandle, IntPtr)
                        Dim ProcessId As Integer = element.Current.ProcessId
                        If ProcessId = Process.GetCurrentProcess().Id Then
                            Dim CurrentForm As Form = Nothing
                            If Not MyMainForm.IsHandleCreated Then Return
                            MyMainForm.Invoke(New MethodInvoker(
                                Sub()
                                    CurrentForm = Application.OpenForms.
                                           OfType(Of Form)().
                                           FirstOrDefault(Function(f) f.Handle = NativeHandle)
                                End Sub))
                            If CurrentForm IsNot Nothing Then
                                Dim FormName As String = FormsHandler.FirstOrDefault(Function(f) f?.Name = CurrentForm.Name)?.Name
                                If Not String.IsNullOrEmpty(FormName) Then
                                    RemoveHandler CurrentForm.Resize, ResizeHandler
                                    FormsHandler.Remove(FormsHandler.Where(Function(fn) fn.Name = FormName).First())
                                End If

                                AddHandler CurrentForm.Resize, ResizeHandler
                                FormsHandler.Add(CurrentForm)

                                CurrentForm.Invoke(New MethodInvoker(
                                Sub()
                                    CurrentForm.Text = CurrentForm.Text & $" ({CurrentForm.Width}, {CurrentForm.Height})"
                                End Sub))
                            End If
                        End If
                    End Sub)

        Application.Run(MyMainForm)

    End Sub

End Module
Run Code Online (Sandbox Code Playgroud)