none
How can I detect when parentform's properties are changing? RRS feed

  • Question

  • I am working on a couple of UserControls lately and this time is a custom TitleBar. What I want to do is to detect when ParentForm's properties like ControlBox for example are changing by developer in Design Time and then update my TitleBar. I added a Timer into my UserControl to do this "work" and it works, but I think this isn't the most appropriate approach...

    Private Sub Timer_Tick(sender As Object, e As EventArgs) Handles Timer.Tick
    	
    	Me.ControlBox = Me.ParentForm.ControlBox	
    	If ParentForm.ControlBox = True Then
    		ControlsBox_FlowLayoutPanel.Visible = True
    	Else ControlsBox_FlowLayoutPanel.Visible = False
    	End If
    	
    	Me.MinimizeBox = Me.ParentForm.MinimizeBox
    	If ParentForm.MinimizeBox = True Then 
    		MinimizeButton_PictureBox.Visible = True 
    	Else MinimizeButton_PictureBox.Visible = False
    	End If
    	
    	Me.MaximizeBox = Me.ParentForm.MaximizeBox
    	If ParentForm.MaximizeBox = True Then 
    		MaximizeButton_PictureBox.Visible = True
    	Else MaximizeButton_PictureBox.Visible = False
    	End If
    	
    End Sub
    Is there any other way to do that and not by using a Timer? For example, to detect ParentForm's Text property and then update my UserControl's Text, I do something like this...
    Private WithEvents _ParentForm As Form
    
    Protected Overrides Sub OnParentChanged(e As EventArgs)
    	MyBase.OnParentChanged(e)
    	_ParentForm = Me.ParentForm
    	Call ParentForm_TextChanged()
    End Sub
    
    Private Sub ParentForm_TextChanged() Handles _ParentForm.TextChanged
    	If _ParentForm Is Nothing Then
    		FormTitle_Label.Text = FormTitle_Label.Text
    	Else
    		FormTitle_Label.Text = _ParentForm.Text
    	End If
    	Invalidate()
    End Sub
    Is there anything similar for properties like ControlBox, MinimizeBox and MaximizeBox?
    Thank you in advance!!!
    Wednesday, April 18, 2018 1:43 PM

Answers

  • IronRazerz: Just to show that creating your own form class and making the forms in a new project inherit that form works,  I used the code from the one link I gave you on DIC to create a class library (dll) of my custom Form class.  Then I made a new project and forced my main form (Form1) to inherit from that form.

     In my honest opinion,  creating your own form class would be better than trying to hack things together that may not be reliable or may cause problems in the VS designer.  Just my opinion though.  8)...

    My good friend IronRazerz, thank you one more time for your valuable help, you always do that!!! I am sincerely interested to follow your opinion... Besides I wanted to do something like this from the beginning but I didn't know how. For now I'll post a solution which I found for my initial question and then I'll study yours!!! :)

    Well, here is an example on how we can detect
    when ParentForm's properties are changing and then do our stuff:
    Private WithEvents _ParentForm As Form
    
    Protected Overrides Sub OnParentChanged(e As EventArgs)
    	MyBase.OnParentChanged(e)
    	_ParentForm = Me.ParentForm
    	Call ParentForm_TextChanged()
    	Call ParentForm_StyleChanged()
    End Sub
    
    Private Sub ParentForm_TextChanged() Handles _ParentForm.TextChanged
    	If _ParentForm IsNot Nothing Then FormTitle_Label.Text = _ParentForm.Text
    	Invalidate()
    End Sub
    
    Private Sub ParentForm_StyleChanged() Handles _ParentForm.StyleChanged
    	If _ParentForm IsNot Nothing Then
    		If _ParentForm.ControlBox = True Then ControlsBox_FlowLayoutPanel.Visible = True Else ControlsBox_FlowLayoutPanel.Visible = False
    		If _ParentForm.MinimizeBox = True Then MinimizeButton_PictureBox.Visible = True Else MinimizeButton_PictureBox.Visible = False
    		If _ParentForm.MaximizeBox = True Then MaximizeButton_PictureBox.Visible = True Else MaximizeButton_PictureBox.Visible = False
    	End If
    End Sub



    Thursday, April 19, 2018 9:24 AM

All replies

  • Try a UserControl like this:

    Public Class MyUserControl
     
        Dim previousParentForm As Form = Nothing
     
        Private Sub MyUserControl_ParentChanged(sender As Object, e As EventArgs) Handles MyBase.ParentChanged
     
            If DesignMode Then
                If previousParentForm IsNot Nothing Then RemoveHandler ParentForm.StyleChanged, AddressOf ParentFormStyleChanged
                previousParentForm = ParentForm
                AddHandler ParentForm.StyleChanged, AddressOf ParentFormStyleChanged
            End If
     
        End Sub
     
        Private Sub ParentFormStyleChanged(sender As Object, e As EventArgs)
    
            Beep()
    
        End Sub
    End Class
    

     

    Replace Beep with your code.

     

    Wednesday, April 18, 2018 3:05 PM
  • Simonetos,

    What do you call "design time"? The design time is just coding where some coding is done automatically in the xx.Designer.vb code files if you use a designer but there happens nothing as the code does not run.  

    Be aware that Windows Forms is only one of the endless usages of VB currently. It is  not anymore like in the time of the Olympian gods. 

    Windows forms forum

    https://social.msdn.microsoft.com/Forums/windows/en-US/home?forum=winforms

    However, in this VB forum people is not so strict to call it OT if it is not direct related to the language. 


    Success
    Cor


    Wednesday, April 18, 2018 3:17 PM
  • Simonetos,

    What do you call "design time"? The design time is just coding where some coding is done automatically in the xx.Designer.vb code files if you use a designer but there happens nothing as the code does not run.  


    Success
    Cor


    Hey Cor

    I believe Simonetos means the User Control needs to detect if the Form changes in the designer window somehow. Such as you drag the User Control onto the Form and somebody alters the Form in design time detect the changes for whatever reason. A timer in the User Control will run in design time as I've used one before for some reason but can't remember now for a custom control.


    La vida loca

    Wednesday, April 18, 2018 3:54 PM
  • I implemented basically Leshays code adding the handler with a timer. However there is an INotifyPropertyChanged event that I do not know how to subscribe to for a parent (Form) at this point. I'm still searching on that.

    Note that without using the timer the code would crash when the Label was being placed onto the Form.

    In the image the Labels text went to False once the ControlBox was set to False in the properties window for the Form in design time.

    Option Strict On
    
    Public Class MyLabel
        Inherits Label
    
        Public Declare Function InvalidateRect Lib "User32" Alias "InvalidateRect" (ByVal hWnd As Int32, ByVal lpRect As IntPtr, ByVal bErase As Boolean) As Boolean
    
        Dim MouseIn As Boolean = False
    
        Dim MeLineColor As Color
    
        Dim MeLineWidth As UInt32
    
        Dim ParentHandle As IntPtr
    
        Friend WithEvents myTimer1 As New Timer
    
        Dim F1 As New Form
    
        Public Sub New()
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
            Me.SetStyle(ControlStyles.Selectable, True)
            Me.Font = New Font("Cambria", 8)
            Me.BorderStyle = Windows.Forms.BorderStyle.Fixed3D
            Me.BackColor = Color.White
            Me.AutoSize = False
            Me.Size = New Size(190, 30)
            Me.MinimumSize = New Size(190, 30)
            Me.MaximumSize = New Size(190, 30)
            Me.TextAlign = ContentAlignment.TopCenter
            myTimer1.Interval = 2000
            myTimer1.Start()
        End Sub
    
        Public Property LineColor() As Color
            Get
                Return LineColor
            End Get
            Set(ByVal value As Color)
                MeLineColor = value
            End Set
        End Property
    
        Public Property LineWidth() As UInt32
            Get
                Return LineWidth
            End Get
            Set(ByVal value As UInt32)
                MeLineWidth = value
            End Set
        End Property
    
        Public Property HandleToUse() As IntPtr
            Get
                Return HandleToUse
            End Get
            Set(ByVal value As IntPtr)
                ParentHandle = value
            End Set
        End Property
    
        Protected Overrides Sub OnMouseEnter(e As EventArgs)
            InvalidateRect(0, ParentHandle, True)
            MouseIn = True
            MyBase.OnMouseEnter(e)
        End Sub
    
        Protected Overrides Sub OnMouseLeave(e As EventArgs)
            InvalidateRect(0, ParentHandle, True)
            MouseIn = False
            MyBase.OnMouseLeave(e)
        End Sub
    
        Protected Overrides Sub OnPaint(e As PaintEventArgs)
            If MouseIn = True Then
                Using Brush1 As New SolidBrush(MeLineColor)
                    Using Pen1 As New Pen(Brush1, MeLineWidth)
                        Using g As Graphics = Graphics.FromHwnd(ParentHandle)
                            g.DrawLine(Pen1, Me.Left, Me.Bottom + 1, Me.Right, Me.Bottom + 1)
                        End Using
                    End Using
                End Using
            End If
            MyBase.OnPaint(e)
        End Sub
    
    
        Private Sub myTimer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles myTimer1.Tick
            myTimer1.Stop()
            Try
                F1 = CType(Me.Parent, Form)
                AddHandler F1.StyleChanged, AddressOf F1_StyleChanged
            Catch ex As Exception
            End Try
        End Sub
    
        Private Sub F1_StyleChanged(sender As Object, e As EventArgs)
            Me.Text = F1.ControlBox.ToString
        End Sub
    
    End Class


    La vida loca

    Wednesday, April 18, 2018 5:49 PM
  • Hey John,

    I don't know that.  A form is no parent from a control. A control is just an object in the control-collection of a form or in the collection of another control on a higher level.

    This means that an object instanced in one class, should know about this its parent object. This is seen as bad practice.  In VB Windows forms default instances its objects (not in other program languages). This is seen as bad done.  

    Therefore I'm sure that you managed to do it. You always surprises me around that. But that does not mean we should do if it is normal. 

    It is like this guy (I was searching the statue you made, but then I saw you had replied in this thread). 

    :-)

     



    Success
    Cor

    Wednesday, April 18, 2018 5:55 PM
  • Nice done but that I told already. (I never thought that the background compiling for errors could do this as well)

    :-)

    I guess it goes wrong if the usercontrol becomes a control in a groupbox

    :-)


    Success
    Cor



    Wednesday, April 18, 2018 6:06 PM
  •  No disrespect to Viorel or John but,  you are going to find that Viorel's answer will cause the same "Object not set to an instance" exception you where getting with the example I suggested on the Dream In Code forum.  You will also find that Mr. Monkeyboy's code uses a Timer which is what you wanted to get away from using.

     As I just posted in your thread on DIC,  perhaps you should consider taking a different approach.  Either let the user set these options through public properties/methods,  or create your own form class (dll) which looks/acts like you want and let the user of the class make their project's Forms Inherit from that Form class.


    If you say it can`t be done then i`ll try it

    Wednesday, April 18, 2018 6:25 PM
  • Hey John,

    I don't know that.  A form is no parent from a control. A control is just an object in the control-collection of a form or in the collection of another control on a higher level.

    This means that an object instanced in one class, should know about this its parent object. This is seen as bad practice.  In VB Windows forms default instances its objects (not in other program languages). This is seen as bad done.  

    Therefore I'm sure that you managed to do it. You always surprises me around that. But that does not mean we should do if it is normal. 

    It is like this guy (I was searching the statue you made, but then I saw you had replied in this thread). 

    :-)

     



    Success
    Cor

    LOL. Tks Cor. Here's Mr. Land Crab again!


    La vida loca

    Wednesday, April 18, 2018 6:45 PM
  •  Just to show that creating your own form class and making the forms in a new project inherit that form works,  I used the code from the one link I gave you on DIC to create a class library (dll) of my custom Form class.  Then I made a new project and forced my main form (Form1) to inherit from that form.

     In my honest opinion,  creating your own form class would be better than trying to hack things together that may not be reliable or may cause problems in the VS designer.  Just my opinion though.  8)

     Here is what the Form looks like in the VS designer window when I make it inherit from my custom form class...

     

     And here is what it looks like at runtime....


    If you say it can`t be done then i`ll try it

    Wednesday, April 18, 2018 7:14 PM
  • Viorel: Try a UserControl like this:...

    Thank you very much for your answer my friend Viorel!!!

    Your example worked, but as IronRazerz said, it cause an error which says "Object reference not set to an instance of an object." and this happens everytime I rebuild or remove and re add my UserControl into a form, when I try to change properties like ControlBox, MinimizeBox and MaximizeBox of parent form. I found a solution and I will post it in a few minutes!!!

    Thank you for your precious time!!! :)




    Thursday, April 19, 2018 8:47 AM
  • Mr. Monkeyboy: I implemented basically Leshays code adding the handler with a timer. However there is an INotifyPropertyChanged event that I do not know how to subscribe to for a parent (Form) at this point. I'm still searching on that.

    Note that without using the timer the code would crash when the Label was being placed onto the Form.

    In the image the Labels text went to False once the ControlBox was set to False in the properties window for the Form in design time...

    Thank you very much for your answer Mr. Monkeyboy but as IronRazerz said, your example uses a Timer which is what I want to get away from using!!! Thank you for your time!!! :)


    Thursday, April 19, 2018 8:57 AM
  • IronRazerz: Just to show that creating your own form class and making the forms in a new project inherit that form works,  I used the code from the one link I gave you on DIC to create a class library (dll) of my custom Form class.  Then I made a new project and forced my main form (Form1) to inherit from that form.

     In my honest opinion,  creating your own form class would be better than trying to hack things together that may not be reliable or may cause problems in the VS designer.  Just my opinion though.  8)...

    My good friend IronRazerz, thank you one more time for your valuable help, you always do that!!! I am sincerely interested to follow your opinion... Besides I wanted to do something like this from the beginning but I didn't know how. For now I'll post a solution which I found for my initial question and then I'll study yours!!! :)

    Well, here is an example on how we can detect
    when ParentForm's properties are changing and then do our stuff:
    Private WithEvents _ParentForm As Form
    
    Protected Overrides Sub OnParentChanged(e As EventArgs)
    	MyBase.OnParentChanged(e)
    	_ParentForm = Me.ParentForm
    	Call ParentForm_TextChanged()
    	Call ParentForm_StyleChanged()
    End Sub
    
    Private Sub ParentForm_TextChanged() Handles _ParentForm.TextChanged
    	If _ParentForm IsNot Nothing Then FormTitle_Label.Text = _ParentForm.Text
    	Invalidate()
    End Sub
    
    Private Sub ParentForm_StyleChanged() Handles _ParentForm.StyleChanged
    	If _ParentForm IsNot Nothing Then
    		If _ParentForm.ControlBox = True Then ControlsBox_FlowLayoutPanel.Visible = True Else ControlsBox_FlowLayoutPanel.Visible = False
    		If _ParentForm.MinimizeBox = True Then MinimizeButton_PictureBox.Visible = True Else MinimizeButton_PictureBox.Visible = False
    		If _ParentForm.MaximizeBox = True Then MaximizeButton_PictureBox.Visible = True Else MaximizeButton_PictureBox.Visible = False
    	End If
    End Sub



    Thursday, April 19, 2018 9:24 AM
  • For those who sees this code, if you try it in a usercontrol it gives almost more lines marked with errors than without. 

    However, it shows very well what I told in this thread, the code is 80% depended from the instanced object (not the class) in which it is used.

    In fact the usercontrol adds nothing and therefore a usercontrol is only making the program more difficult to maintain. 

    It could be as well a simple section in the program. 

    But we were all once beginners and probably all made the same mistakes. 



    Success
    Cor




    Thursday, April 19, 2018 11:22 AM
  • Cor Ligthert: For those who sees this code, if you try it in a usercontrol it gives almost more lines marked with errors than without. 

    However, it shows very well what I told in this thread, the code is 80% depended from the instanced object (not the class) in which it is used.

    In fact the usercontrol adds nothing and therefore a usercontrol is only making the program more difficult to maintain. 

    It could be as well a simple section in the program. 

    But we were all once beginners and probably all made the same mistakes.

    Sorry if I misunderstand your words, but what is wrong with my code example? I can't get what do you mean. For what kind of errors are you talking about? I am already using it in a UserControl and works 100%!!!

    Mediocrity is my greatest enemy!!!


    Thursday, April 19, 2018 6:07 PM
  • Simonetos,

    To get it running means not that it is correct. 

    However, I tried it (created a usercontrol and pasted your code in). I used it in a clean form and got many errors, but I've not your complete usercontrol. 

    There is no problem if you create a complete new windows forms project, only create a groupbox and drag in that your usercontrol.

    If there is no error, than my comment is because of the fact that I had only the code you've shown and it can be ignored. If you get errors, I assume you understand better what I mean. 



    Success
    Cor

    Friday, April 20, 2018 4:40 PM
  • Cor Ligthert: To get it running means not that it is correct. 

    However, I tried it (created a usercontrol and pasted your code in). I used it in a clean form and got many errors, but I've not your complete usercontrol. 

    There is no problem if you create a complete new windows forms project, only create a groupbox and drag in that your usercontrol.

    If there is no error, than my comment is because of the fact that I had only the code you've shown and it can be ignored. If you get errors, I assume you understand better what I mean.

    I did as you said and I get no errors!!! So, the reason you get errors is because of the fact that you have only the code I've shown, as you already said. Thank you for the trick by the way!!!

    Mediocrity is my greatest enemy!!!

    Friday, April 20, 2018 5:08 PM