【问题标题】:How to set an event for MDI child forms without adding code to each form?如何在不向每个表单添加代码的情况下为 MDI 子表单设置事件?
【发布时间】:2018-02-05 17:21:31
【问题描述】:

我想在所有打开的子窗体上为某种类型的控件设置背景颜色。我有一个 MdiParent 表单,用于在其内部打开其他表单。我不想为每个子表单添加代码,因为这会非常广泛。这将用作应用程序的主题功能,因此我希望它根据主窗体中的逻辑自动更改背景颜色。是否存在可以触发所有 Form.Load 事件的全局事件?

到目前为止,我已经在父窗体中创建了一个事件,但它不适用于嵌套控件

Private Sub frmMain_MdiChildActivate(sender As Object, e As EventArgs) Handles Me.MdiChildActivate
    Dim ParentControl As frmMain = sender
    Dim ChildControl = ParentControl.ActiveControl

    If ChildControl IsNot Nothing Then
        For Each FormControl As Control In ChildControl.Controls
            If FormControl.GetType = GetType(GroupBox) Then
                RemoveHandler FormControl.Paint, AddressOf PaintBorderlessGroupbox
                AddHandler FormControl.Paint, AddressOf PaintBorderlessGroupbox
            End If
        Next
    End If

End Sub

【问题讨论】:

  • 当然有,你想做什么?
  • 创建一个包含所有共享属性值的静态类(VB 中的模块)。你也可以从Form继承并根据你的需要进行自定义
  • @Codexer 我在父窗体中创建了一个 MdiChildActivate 事件,该事件为我想在子窗体中更改的每个控件创建一个 Paint 事件处理程序。问题是这不适用于嵌套控件。
  • @jonathana 除了父表单之外,我不想在现有表单中添加任何代码
  • 如果您不想添加任何代码,您打算如何解决问题?我同意,为共享属性创建一个模块。

标签: vb.net winforms event-handling mdichild mdiparent


【解决方案1】:

我能够通过使用Form.MdiChildActivate 并将事件添加到基于EventEventHandler 的适当控件来完成此操作。

Private Sub frmMain_MdiChildActivate(sender As Object, e As EventArgs) Handles Me.MdiChildActivate
    Dim ParentForm As frmMain = sender
    Dim ChildForm = ParentForm.ActiveMdiChild
    Dim EventName = "Paint"
    Dim EventHandlerName = "PaintBorderlessGroupBox"

    If ChildForm IsNot Nothing Then
        AddEventToControls(ChildForm, GetType(GroupBox), EventName, EventHandlerName)
    End If
End Sub

Private Sub AddEventToControls(Control As Control, ControlType As Type, ControlEventName As String, ControlEventMethod As String)
    For Each ChildControl In Control.Controls
        If ChildControl.GetType = ControlType Then

            If ChildControl.Controls.Count > 0 Then
                AddEventToControls(ChildControl, ControlType, ControlEventName, ControlEventMethod)
            End If

            Dim EventMethod = Me.GetType().GetMethod(ControlEventMethod, BindingFlags.NonPublic Or BindingFlags.Instance)
            Dim ControlEvent As EventInfo = ControlType.GetEvent(ControlEventName)
            Dim del = [Delegate].CreateDelegate(ControlEvent.EventHandlerType, Me, EventMethod)

            ControlEvent.RemoveEventHandler(ChildControl, del)
            ControlEvent.AddEventHandler(ChildControl, del)
        End If
    Next
End Sub

AddEventToControls() 的调用将处理程序分配给控件以及它也将应用于的任何子控件。在这种情况下,我将Control.Paint 事件设置为以特定方式绘制GroupBox。这可能不是完成此任务的最干净的方法,但我能够为所有子表单创建一个“全局事件”,而无需触及每个表单上的代码。

【讨论】:

  • 这对子表单有何作用?在您的代码示例中,您已将 ChildForm 设置为控件,而不是表单。因此,它不会回答您自己的问题(“我想为所有打开的表单上的某种类型的控件设置背景颜色。我有一个用于打开其他表单的父表单。” )。如果您能展示这对子表单而不是子控件的工作原理,很高兴删除反对票。
  • @AJD 这适用于所有子表单,因为它们包含在父表单中。查看父窗体的活动控件时,您会发现在这种情况下返回子窗体,因为我们在 MdiChildActivate 事件处理程序中。使用 Form.ActiveControl 将子窗体作为控件返回。我已将其更改为 Form.ActiveMdiChild,这将返回一个仍用作 AddEventToControls() 中的控件的 Form。
  • OP 中缺少上下文,我的印象是子表单是独立于父表单的衍生表单。我的另一个印象是颜色的变化发生在孩子们产卵之后。在您的答案中添加此上下文并清楚地解释您上面所说的内容将有助于未来的研究人员。那我觉得这个答案很有用。
  • @AJD 我同意缺少上下文。我更改了 OP 以反映表单之间的关系并明确说明这是针对 MdiForms 的。
  • 好的 - 现在更清楚了。您是否考虑过如何为已加载的表单执行此操作?
【解决方案2】:

在您的父表单中,保留所有已激活的子表单的集合。然后,您可以遍历该集合并更改每个集合的相关控件属性。

For Each ChildForm in MyCollection
    ChildForm.TextBox.BackColor = Red
Next

当然:

  • 父窗体必须可以访问 ChildForm 控件
  • ChildForm 必须仍然存在(即平均未关闭 时间)
  • 您无法检查 ChildForm 关闭,因为您没有添加任何 向 ChildForm 发送代码以发出此类事件的信号。
  • 当您尝试更改表单时,您必须处理异常 已关闭。

ChangeColour() 的 ChildForm 设计中包含一个方法要容易得多,该方法是由事件触发还是直接调用是您的设计决定。并包含一个方法来告诉父窗体何时 ChildForm 死亡,以便它停止寻找它。

【讨论】:

    猜你喜欢
    • 2013-09-03
    • 2016-12-15
    • 2015-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多