Click here to Skip to main content
15,885,537 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
Hi,

I'm programming a windows form application, I'm having a problem in implementing a code to my user controls,

let's say, all my forms inherit from my base class and in my base class I have the code below,

VB
Public Class BaseForm
    Inherits System.Windows.Forms.Form

    Protected Overrides Sub OnVisibleChanged(e As System.EventArgs)
        MyBase.OnVisibleChanged(e)

        If Me.Visible Then ' create Handler to each Button when Form is shown (becomes visible)
            For Each myControl As Control In Me.Controls
                If myControl.GetType Is GetType(Button) Then
                    AddHandler myControl.Click, AddressOf TestModul.ClickHandler
                End If
            Next
        Else ' remove Handler from each Button when Form is left (becomes unvisible)
            For Each myControl As Control In Me.Controls
                If myControl.GetType Is GetType(Button) Then
                    RemoveHandler myControl.Click, AddressOf TestModul.ClickHandler
                End If
            Next
        End If

    End Sub
End Class


The test module is as follows:

VB
Module TestModul
    Public Sub ClickHandler(sender As Object, e As System.EventArgs)

        Dim mySender As Control = sender
        MessageBox.Show(mySender.Name + vbCrLf + mySender.Parent.Name)
        If (mySender.Parent.GetType().ToString().Contains("UserControl")) Then
            MessageBox.Show("Its a user control")
        End If

    End Sub
End Module

So far everything is working properly, but the problem is with implementing the code to my usercontrols which all inherit from my baseusercontrol which is written below:

VB
Public Class BaseUserControl
    Inherits System.Windows.Forms.UserControl

   Protected Overrides Sub OnVisibleChanged(e As System.EventArgs)
        MyBase.OnVisibleChanged(e)

        If Me.Visible Then ' create Handler to each Button when Form is shown (becomes visible)
            For Each myControl As Control In Me.Controls
                If myControl.GetType Is GetType(Button) Then
                    AddHandler myControl.Click, AddressOf TestModul.ClickHandler
                End If
            Next
        Else ' remove Handler from each Button when Form is left (becomes unvisible)
            For Each myControl As Control In Me.Controls
                If myControl.GetType Is GetType(Button) Then
                    RemoveHandler myControl.Click, AddressOf TestModul.ClickHandler
                End If
            Next
        End If

    End Sub

End Class


this procedure must do as follows, anytime a button is pressed it must show me a messagebox and display the name of that button and the form which contains the button.

What I have tried:

as is traced it it does not enter this condition,

VB
If myControl.GetType Is GetType(Button) Then


and see's it as a false condition. I removed the If statement and saw that again it doesn't read the line of code
VB
AddHandler myControl.Click, AddressOf TestModul.ClickHandler

so again the change will not be done on the buttons.

Well in on of my forms it's working, because I opened it and manually removed the line of inheritence after the name of those classes, I just removed the line ' Inherits baseusercontrol' and rewrote it. then it worked.


But I shouldn't do this for all other classes. What would be the automated way to that?


In advance thank you for your help.
Posted
Updated 16-Jul-16 10:03am
v2
Comments
m.r.m.40 16-Jul-16 6:16am    
The codes above are given to me by a professional member 'Ralf Meier'.
Richard MacCutchan 16-Jul-16 7:01am    
Then you should ask Ralf Meier for help.
m.r.m.40 16-Jul-16 7:04am    
I don't know how to contact him.
I just found out what the problem is. I'll just post it here.
Richard MacCutchan 16-Jul-16 7:28am    
Go back to the message where he gave you this code.
Ralf Meier 16-Jul-16 15:56pm    
I would not add this code to the usercontrol. I would do it in the Form as described. When you iterate through the Forms.control-collection you could also check if each of those controls have also child-controls in it - in this case you check the child-controls and connect them (if necessary) also to the handler. See my solution (2) to this ...

To let act your Control as a Container you Need to derive from ContainerControl. In your case the form is the Container for the button you placed on your control.

For tests it is very convinient to derive from Panel. This because you can show e.g. a border.

[Edit]
Finally: The harder (but probably correct) way is described here on CP Designing Nested Controls[^]

Hope it helps.

[Edit1] The OnVisible Story
Note: I would suggest to avoid adding and removing event handlers frequently like you do it in your code. Instead you should try with checking parent.Visible in your event handler.

Here an idea how you can solve the "OnVisible" request as a Default behaviour of your control. I did it in c# (I don't know VB) but I'm sure it is no Problem for you to convert it to VB.
C#
 public partial class MyPanel : Panel // ContainerControl //UserControl
 {
     Form lastParent= null;

     // Install Event handler to the control
     protected override void OnParentChanged(EventArgs e)
     {
         // Call base class
         base.OnParentChanged(e);

         // Remove handler from previous hosting form
         if (lastParent != null)
         {
             lastParent.VisibleChanged -= ParentVisibleChanged;
             lastParent = null;
         }

         // Find the new hosting form. Most probably the same, but who knows
         Control parent = this.Parent;
         while (parent != null)
         {
             if (parent is Form)
             {
                 lastParent = (Form)parent;
                 lastParent.VisibleChanged += ParentVisibleChanged;
                 break;
             }
             parent = parent.Parent;
         }
     }

     protected void ParentVisibleChanged(object sender, EventArgs e)
     {
         // Debug only
         MessageBox.Show("ParentVisibleChanged");

         // Do what you need to do for form visible change
         // Should always be true.
         if (lastParent != null)
         {
             if (lastParent.Visible)
             {
             }
             else
             {
             }
         }
     }
  ...
  .....
}
 
Share this answer
 
v5
Comments
Ralf Meier 19-Jul-16 14:43pm    
I don't agree with your opinion of the Eventhandling. I think, that it is not good, if an unneeded Eventhandler is still attached to an Event. If a Form is not visible (hided by command) is is not necessary to keep the Eventhandling of this Form alive ...
[no name] 19-Jul-16 14:51pm    
You are probably right, I Need to think again about this. Thanks for waking me up on this matter.
BillWoodruff 23-Jul-16 23:07pm    
+5
fyi: these are the Controls that inherit from ContainerControl:

            System.Windows.Forms.Form
            System.Windows.Forms.PropertyGrid
            System.Windows.Forms.SplitContainer
            System.Windows.Forms.ToolStripContainer
            System.Windows.Forms.ToolStripPanel
            System.Windows.Forms.UpDownBase
            System.Windows.Forms.UserControl

the inheritance chain for Panel:

System.Object
  System.MarshalByRefObject
    System.ComponentModel.Component
      System.Windows.Forms.Control
        System.Windows.Forms.ScrollableControl
          System.Windows.Forms.Panel
            System.Windows.Forms.Design.ComponentEditorPage
            System.Windows.Forms.FlowLayoutPanel
            System.Windows.Forms.SplitterPanel
            System.Windows.Forms.TableLayoutPanel
            System.Windows.Forms.TabPage
            System.Windows.Forms.ToolStripContentPanel
[no name] 24-Jul-16 1:46am    
Thank you very much.
I would change the posted methods like this :

VB
Protected Overrides Sub OnVisibleChanged(e As System.EventArgs)
        MyBase.OnVisibleChanged(e)

        CheckControlCollection(Me , Me.Visible)

End Sub


VB
Private Sub CheckControlCollection(myHost As Control , state as boolean)
        For Each myControl As Control In myHost.Controls
            If myControl.GetType Is GetType(Button) Then
                if state then AddHandler myControl.Click, AddressOf TestModul.ClickHandler
                if not state then RemoveHandler myControl.Click, AddressOf TestModul.ClickHandler
            End If

            If myControl.Controls.Count > 0 Then
                CheckControlCollection(myControl , state) ' <- I have modified this line because of a mistake in it ...
            End If
        Next
End Sub


But please note - this code is not tested ...
Both methods still belong to your baseform. You don't need to integrate it to the usercontrol or any other containercontrol.
Your code in your usercontrol doesn't work because the usercontrol doesn't change it's Visible-State. If you want to do it in the usercontrol in the same way you should override annother method - but I prefer THIS way ...

Additional :
If you have further question (to this code or something else) you only need to comment this answer / solution or you should comment one of my comments. In both cases I get a message and if I'm online again I answer - if possible ... ;-)

Additional (2) :
>> I modified the code because of a mistake in it ...


Additional (3) - modified ClickHandler :
VB
Public Sub ClickHandler(sender As Object, e As System.EventArgs)

    Dim mySender As Control = sender
    Dim myChildPath As String = mySender.Name

    Do
        If mySender.Parent Is Nothing Then Exit Do
          mySender = mySender.Parent
        myChildPath += vbCrLf + mySender.Name
    Loop

    MessageBox.Show(myChildPath)

End Sub
 
Share this answer
 
v7
Comments
m.r.m.40 18-Jul-16 2:10am    
Thank you, but no, it's not working on usercontrols.
Ralf Meier 18-Jul-16 3:36am    
I think, you understood me wrong. This code is not designed to work on usercontrols - it should work also on the (base-)form. It replaces the code-samples I gave to you in the other question ...

Do you really want to have a code like this working on usercontrols ?
m.r.m.40 18-Jul-16 3:51am    
Yes, this new code and the previous one both work as well,
the problem I have now is how to have this module working on my usercontrols.

Ralf Meier 18-Jul-16 6:47am    
I'm sorry - I could not follow you. Where do you have the Problem ?
You don't have anything to change on your UserControls. Every UserControl is placed on a Form which derives from your BaseForm which has the code and can detect the Button on the Baseform as well as it could detect it on a UserControl on the Baseform as well as it could detect it on a Control in a Control in a Control on the Baseform.

Please give me an example for your issue ...
m.r.m.40 19-Jul-16 1:09am    
Something came into my mind,

These lines of code:

If Me.Visible Then
CheckControlCollection(Me, Me.Visible)
Else
CheckControlCollection(Me, Me.Visible)
End If

do not need 'if' and 'else' statement. the single line
CheckControlCollection(Me, Me.Visible)
will work as well.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900