.net 向项目中的所有窗体添加事件

rn0zuynd  于 2023-02-10  发布在  .NET
关注(0)|答案(2)|浏览(89)

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

yiytaume

yiytaume1#

下面尝试实现一个针对该问题的Automation解决方案。

    • 问题是:**

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

  • Element.Name(对应于Windows标题)
  • 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()事件后,所有窗体的标题都将报告窗口的当前大小。

    • 测试环境**:

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
    • 注:**

之前的代码放置在应用程序起始窗体中(用于测试),但最好在需要时将模块包含在项目中,而不触及当前代码。
要使其正常工作,请添加一个包含Public Sub Main()的新模块(名为Program),并更改Project属性以从Sub Main()启动应用程序,而不是从Form启动。
删除Use Application Framework上的复选标记,然后从Startup object组合框中选择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
ryhaxcpt

ryhaxcpt2#

您可以按照@Jimi的建议使用自动化。
您可以使用My.Application.OpenForms循环访问所有打开的窗体,但在打开新窗体时,它将没有帮助。
您可以创建一些继承System. Forms. Form的ReportSizeForm类,并将窗体的继承从常规System.Windows.Forms.Form更改为ReportSizeForm。

相关问题