0

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
Programmer
  • 459
  • 5
  • 20
  • Sure there is, what have you attempted to do? – Trevor Feb 05 '18 at 17:29
  • 1
    create a static class (module in VB) that will contain all shared properties values. also you can also inherit from `Form` and customize it according to your needs – Jonathan Applebaum Feb 05 '18 at 17:38
  • @Codexer I have created an MdiChildActivate event in the parent form that creates a Paint event handler for each control I want to change in the Child form. The issue is that this doesn't work for nested controls. – Programmer Feb 05 '18 at 17:42
  • @jonathana I don't want to add any code to existing forms besides the parent form – Programmer Feb 05 '18 at 17:50
  • If you don't want to add any code how do you plan on solving the problem? I agree, make a module for the shared properties. – Jacob H Feb 05 '18 at 17:52
  • @programmer OK after i see your code i understand your question better...if you will find how to do it without adding code to existing froms let me know (without sarcasm). – Jonathan Applebaum Feb 05 '18 at 17:54
  • @JacobH This is why I'm asking for any advice. – Programmer Feb 05 '18 at 17:55
  • @jonathana I was able to make this happen building off of what I posted. The code is in the answer below. – Programmer Feb 05 '18 at 21:51

2 Answers2

2

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.

Programmer
  • 459
  • 5
  • 20
  • 1
    How does this work for Child forms? In your code example, you have set ChildForm to a control, not a form. As such, it does not answer your own question (_"I would like to set the background color for a certain type of control on all forms that open. I have a parent form that is used to open the other forms."_).Happy to remove the downvote if you can show how this works for Child forms, not Child controls. – AJD Feb 06 '18 at 04:46
  • @AJD This works for all of the child forms because they are contained within the parent form. When looking through the active controls for the parent form, you will find the child form is returned in this case because we are in the MdiChildActivate event handler. Using Form.ActiveControl returns the child form as a Control. I've changed it to Form.ActiveMdiChild and this returns a Form which is still used as a Control in AddEventToControls(). – Programmer Feb 06 '18 at 15:40
  • that context was missing from the OP, I had the impression that the child forms were spawned forms independent of the parent. The other impression I had was that the change of colour occurred after the children were spawned. Adding this context and a clear explanation of what you said above to your answer will help future researchers. Then I would think the answer is useful. – AJD Feb 06 '18 at 19:16
  • @AJD I agree that the context was missing. I changed the OP to reflect the relationship between forms and to add clarity that this is for MdiForms. – Programmer Feb 06 '18 at 19:26
  • OK - clearer now. Have you considered how you could do it for Forms that have already been loaded? – AJD Feb 07 '18 at 04:10
0

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.

AJD
  • 2,400
  • 2
  • 12
  • 22