Search code examples
vb.netuser-controlsvisual-studio-2017

Issue with ParentForm's property changing detection


I am working on a custom TitleBar (UserControl). What I want to do is to detect when ParentForm's Text property is changing by developer in Design Time and then update TitleBar's Text property.

Before I start looking for this on the web, I had add a Timer into my UserControl to do this "work". Something like this...

Private Sub Timer_Tick(sender As Object, e As EventArgs) Handles Timer.Tick
    FormTitle_Label.Text = Me.ParentForm.Text
End Sub

Then I realized that this isn't the most appropriate approach. So I found something like this...

Protected Overrides Sub OnCreateControl()
    MyBase.OnCreateControl()
    AddHandler Me.FindForm.TextChanged, AddressOf ParentForm_TextChanged 
    FormTitle_Label.Text = Me.FindForm.Text
End Sub

Private Sub ParentForm_TextChanged(sender As Object, e As EventArgs)
    FormTitle_Label.Text = Me.FindForm.Text
End Sub

It partly works but, everytime I rebuild or remove and re add my UserControl into a Form, when I try to change the Text property of my ParentForm, I get the error, Property value is not valid. Details: Object reference not set to an instance of an object.. If I close and reopen my project then it works again, but until I rebuild it or remove and re add my UserControl. Any idea why is this happening?


Solution

  • You have to test value of Me.FindForm to Nothing before accesing it's property. Creation of control does not guarantee that it's present on form already.

    Try using OnBindingContextChanged OnParentChanged to track adding/removing your control to parent container. But I'm not sure if it works in design time as well.

    EDIT Added full control code

    Public Class SimonetosTitleBar
        Inherits Control
    
        Private fText As String = "Default title"
        Private WithEvents fOwnerForm As Form
    
        Protected Overrides Sub OnParentChanged(e As EventArgs)
            MyBase.OnParentChanged(e)
            fOwnerForm = FindForm()
            fOwnerForm_TextChanged()
        End Sub
    
        Protected Overrides Sub OnPaint(e As PaintEventArgs)
            MyBase.OnPaint(e)
            e.Graphics.DrawString(fText, Font, SystemBrushes.ControlText, Point.Empty)
        End Sub
    
        Private Sub fOwnerForm_TextChanged() Handles fOwnerForm.TextChanged
            If fOwnerForm Is Nothing Then
                fText = "Default title"
            Else
                fText = fOwnerForm.Text
            End If
            Invalidate()
        End Sub
    
    End Class