如果我想在Form
的标题中显示项目中每个Form
的大小,什么是最好的方法?
我不想在每个Form
中手动放置事件处理程序。
我希望该过程是自动的。
类似重载的Load()
事件,它在resize事件上添加了处理程序。
答案 0 :(得分:5)
这是尝试实现此问题的Automation解决方案。
问题:
将一个或多个事件处理程序附加到Form
项目(或其子集)中的每个现有WinForms
上,而无需编辑/修改这些类的现有代码。
一种可能的解决方案来自Automation
类,该类提供了检测何时打开新Window的方法,并在EventId
时将事件报告给它自己的Automation.AddAutomationEventHandler的订阅者的AutomationEvent设置为WindowPattern模式。
AutomationElement成员必须设置为AutomationElement.RootElement,而Scope
成员必须设置为TreeScope.SubTree。
Automation
,对于每个引起AutomationElement
的{{1}},报告:
-AutomationEvent
(对应于Windows标题)
-Element.Name
-Process ID
(作为整数值)
这些值足以识别属于当前进程的Window;窗口句柄可以识别打开的Window Handle
实例,测试Application.OpenForms()集合。
当表单被选出来时,可以将新的Form
附加到所选的Event Handler
上。
通过扩展此概念,可以创建预定义的事件列表和将这些事件附加到的表单列表。
可能的话,可以在需要时将一个类文件包含在Project中。
请注意,在这种情况下,某些事件将没有意义,因为Event
报告了已经显示的窗口的打开情况,因此Automation
和Load()
事件属于过去。
Shown()
和Form.Resize()
)对此进行了测试,但是为了简单起见,在这里的代码中我仅使用Form.Activate()
。< / p>
这是过程的图形表示。
启动应用程序时,事件处理程序未附加到.Resize()
事件。
仅仅是因为.Resize()
字段设置为Boolean
。
单击按钮,将False
字段设置为Boolean
,从而启用事件处理程序的注册。
注册True
事件后,所有.Resize()
Forms
将报告Window的当前大小。
测试环境:
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
,而无需触及当前代码。
要使其正常工作,请添加一个包含Module
的新Module
(名为Program
),然后更改Project属性以从Public Sub Main()
启动该应用程序Sub Main
中的一个。
删除“使用应用程序框架”上的复选标记,然后从“启动对象”组合中选择“ Sub Main”。
所有代码都可以通过以下修改转移到Form
proc中:
Sub Main
答案 1 :(得分:0)
您可以按照@Jimi的建议使用自动化。
您可以使用My.Application.OpenForms遍历所有打开的表单,但是在打开新表单时无济于事。
可以创建一些继承System.Forms.Form的ReportSizeForm类。并将表单的继承从常规System.Windows.Forms.Form更改为ReportSizeForm。