Programmer
Programmer

Reputation: 479

How to set an event for MDI child forms without adding code to each form?

I would like to set the background color for a certain type of control on all child forms that open. I have an MdiParent form that is used to open the other forms within itself. I don't want to add code to each child form as this would be very extensive. This would be used as a theme feature for the application so I would like to have it automatically change the background colors based on logic in the main form. Is there something like a global event that could trigger for all Form.Load events?

So far I have created an event in the Parent form but it doesn't work for nested controls

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

Upvotes: 0

Views: 1158

Answers (2)

Programmer
Programmer

Reputation: 479

I was able to accomplish this by using Form.MdiChildActivate and adding the event to the appropriate controls based on the Event and EventHandler.

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

The call to AddEventToControls() assigns the handler to the Control and any child controls that it would also apply to. In this case I am setting the Control.Paint event to paint a GroupBox a specific way. This may not be the cleanest method to accomplish this but I was able to create a "Global Event" for all child forms without ever touching the code on each form.

Upvotes: 2

AJD
AJD

Reputation: 2438

In your parent form, keep a collection of all Child Forms that have been activated. You can then traverse that collection and change the relevant control property for each one.

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

Of course:

  • The ChildForm control has to be accessible by the parent form
  • The ChildForm has to still exist (i.e. not been closed in the mean time)
  • You can't check for ChildForm closure because you are not adding any code to the ChildForm to signal such an event.
  • You have to handle the exceptions when you try to change a form that has been closed.

Much easier to include a method in your ChildForm design for ChangeColour(), whether that method is fired by event or direct call is your design decision. And to include a method to tell the parent form when a ChildForm dies so that it stops looking for it.

Upvotes: 0

Related Questions