vb.net - 将事件添加到项目中的所有表单

标签 vb.net winforms events ui-automation

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

最佳答案

这是实现 Automation 的尝试问题的解决方案。
问题:
将一个或多个事件处理程序附加到项目中的每个现有表单(或它们的子集),而无需编辑/修改这些类现有代码。
UIAutomation 提供了一个可能的解决方案,它提供了检测新窗口何时打开并将事件报告给它自己的订阅者的方法Automation.AddAutomationEventHandler , 当 EventIdAutomationEvent设置为 WindowPattern图案。
AutomationElement成员必须设置为 AutomationElement.RootElementScope成员(member) TreeScope.SubTree .Automation , 对于每个 AutomationElement这引发了AutomationEvent ,报告:

  • Element.Name (对应Windows Title)
  • Process ID
  • Window Handle (作为整数值)

  • 这些值足以识别属于当前进程的 Window;窗口句柄允许识别打开的Form例如,测试 Application.OpenForms()收藏。
    当表格被单选出来时,一个新的Event Handler可以附加到 Event选择。
    通过扩展这个概念,可以创建一个预定义的事件列表和一个表单列表来附加这些事件。
    可能,需要时将类文件包含在项目中。
    请注意,某些事件在这种情况下没有意义,因为 Automation当窗口已经显示时报告它的打开,因此 Load()Shown()事件属于过去。

    我已经用几个事件( Form.Resize()Form.Activate() )对此进行了测试,但在这里的代码中我只使用了 .Resize()为简单起见。
    这是该过程的图形表示。
    启动应用程序,事件处理程序未附加到 .Resize()事件。
    只是因为一个 Boolean字段设置为 False .
    单击按钮,Boolean字段设置为 True ,启用事件处理程序的注册。
    .Resize()事件注册后,所有Forms的Title都会报告Window的当前大小。
    Global Handlers
    测试环境 :Visual Studio 2017 pro 15.7.5.Net FrameWork 4.7.1 导入的命名空间:System.Windows.Automation 引用组件 :UIAutomationClientUIAutomationTypesMainForm代码:
    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
    
    注:
    之前的代码放置在应用程序的启动表单中(用于测试),但最好在需要时将模块包含在项目中,而无需触及当前代码。
    要使其正常工作,请添加一个新模块(名为 Program ),其中包含 Public Sub Main() ,并更改项目属性以从 Sub Main() 启动应用程序而不是表格。
    删除 Use Application Framework 上的复选标记并选择Sub Main来自 Startup object组合。
    所有代码都可以转移到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
    

    关于vb.net - 将事件添加到项目中的所有表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51491566/

    相关文章:

    c# - 为什么 System.Design 中的许多 Designer 类都标记为内部类?

    c# - WPF 不活动和事件

    html - Android:如何从特定网页检索有问题的数据?

    c# - LINQ to SQL 连接两个表以根据子表中的两个不同列选择父表两次

    vb.net - VB - 括号!请解释?

    c# - 在 PropertyGrid 中按下 Delete 键时设置属性值

    c# - DataGridView 中的级联组合框

    c# - 刷新 ListView 以显示所选索引?

    c - 事件和信号量的区别

    java - Component.requestFocus 和手动对焦有什么区别