0

I am positive this is something very simple, but I am having complete brain freeze.

I am trying to create my own control which will add some specific functionality to a textbox, and ultimately want this control to be available in my toolbox for use throughout my project.

As an example, I would like to add this new control to my form, change the .Text property to "Something" and then perform some logic on the .Text property in the New() sub, however me.text is always returning "", meaning my logic fails.

Public Class Class1
    Inherits Windows.Forms.TextBox

    Public Sub New()
        If Me.Text = "Something" Then
            MessageBox.Show("Do something")
        End If
    End Sub
End Class

Any advice on how to overcome this hurdle?

Thanks in advance.


Cont....

Ok, so I think some more context would be good here.

This is something I wanted to try, to ease myself back into OOP, as I thought (!) it would be an easy starting point.

Im sure there is a class that I could download that would do everything I need, but I want to learn, not just copy/pase code from wherever I find.

So, the objective is to have a textbox which will also offer a "Caption" property. This property will contain text that is displayed in the textbox until it is clicked, ie "Your Name", and you click to then enter your name (basic stuff).

The original code posted was trying to demonstrate the issue I was having with obtaining the .Text property value in the New() method, as this is where I was trying to do some comparisons between .text and Caption. The code has now changed, and I no longer do this.

The main issue I am having at the moment is... when I add my control to a windows form, the textbox (.text) is empty, and I want it to be populated with the caption.

The code posted below is where I am after much trial and error. It's not too pretty, and theres some things that need to be thought about in more detail, but ultimately my current issue is getting the .text property populated with what I want and that being shown in the designer.

Public Class TextBoxWithCaption
    Inherits Windows.Forms.TextBox

    Dim Caption_Text As String = "Caption"                               ' Define default caption property value
    Dim Caption_TextForeColor As Color = SystemColors.ControlDarkDark

    Dim NoCaption_TextForeColor As Color = SystemColors.WindowText

    Public Sub New()

        MyBase.New()
        Me.Text = Caption
        Me.Width = 150
        Me.ForeColor = Caption_TextForeColor
    End Sub

    Property Caption() As String
        Get
            Return Caption_Text
        End Get
        Set(value As String)

            ' Caption has been changed.
            '

            If Me.Text = Caption_Text Or String.IsNullOrEmpty(Me.Text) Then
                ' Caption property has changed, textbox has no user defined value, update the textbox with the new caption
                Me.Text = value
            End If

            Caption_Text = value

        End Set

    End Property


    Private Sub TextBoxWithCaption_GotFocus(sender As Object, e As EventArgs) Handles Me.GotFocus

        If Me.Text = Caption Then
            ' If the caption is displayed, then clear it ready for the user to type
            Me.Text = ""
            Me.ForeColor = NoCaption_TextForeColor
        End If
    End Sub


    Private Sub TextBoxWithCaption_LostFocus(sender As Object, e As EventArgs) Handles Me.LostFocus

        If Me.Text = "" Then
            ' If the user has not typed anything, restore the caption
            Me.Text = Caption
            Me.ForeColor = Caption_TextForeColor
        End If
    End Sub

End Class
Jimmy
  • 31
  • 5
  • May I ask why you want to do this in the constructor? Could you give an example of what it is you're trying to do? It'd be easier to find workarounds then. -- You could subscribe to the `TextChanged` event, do your work there the first time the text is changed, and then unsubscribe to the event. – Visual Vincent Nov 12 '16 at 21:48
  • Hi, I do not have much experience here and am unsure how to post a reply similar to the original above, where I could type code etc... this appears just for short replies and the like. I will post a more detailed response down below as an answer (not sure if this is the right way of doing things) to give more details. – Jimmy Nov 12 '16 at 22:27
  • Comments are just for short information/questions, yes. Answers should only be submitted if they actually attempt to answer the queston, however you can edit your question via the `Edit` button below it to include more information (which you seem to have found out already :) ). – Visual Vincent Nov 12 '16 at 23:43
  • I understand you want to do this to get back into OOP again, so I'll just say this for future reference: The WinAPI has a built-in window message used to set a text box's caption (here, known as _Cue_) which you can use. See [**this answer**](http://stackoverflow.com/a/4902969/3740093) (can be converted into VB.NET using an online converter). – Visual Vincent Nov 12 '16 at 23:55
  • H Vincent. So sorry for such a long and rude delay in replying, but things happened in life that dragged me away from this, so sorry. I am going to try looking at this again today/tomorrow, but a big thank you for your help! – Jimmy Dec 04 '16 at 16:36
  • It's okay, I'm a very busy guy so I know how it is to not have the time to do stuff. :) – Visual Vincent Dec 04 '16 at 18:46

2 Answers2

1

The initial value of the Text property will always be an empty string.

When changing a property through the designer the constructor will always be called prior to changing the property. This is because the control must be created before you can modify it. Modifying the Text property of a Class1 variable that has not been initialized will throw a NullReferenceException.

If you look in your form's .Designer.vb file in the InitializeComponent() method, it would look something like this:

Private Sub InitializeComponent()
    Me.components = New System.ComponentModel.Container()
    Me.Class11 = New YourNamespace.Class1()
    Me.SuspendLayout()
    '
    'Class11
    '
    Me.Class11.Text = "Something"

    ...
End Sub

So in short: What you're doing is not possible unless you pass a value immediatelly to the constructor.

Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
1

you can still do it and this is correct way because you want call constructor on underlying type

Public Sub New()
    MyBase.New() '<-- this will init yout base text box and now you can use it

    Me.Text = "Something" 

End Sub

But if you had a tool like Resharper, it would warn you about "Virtual member call in constructor", which potentially can produce unexpected results with your property. You can read about online. To solve this issue add this property

Public Overrides NotOverridable Property Text As String
    Get
        Return MyBase.Text
    End Get
    Set (value as string)
        MyBase.Text = value
    End Set
End Property
T.S.
  • 18,195
  • 11
  • 58
  • 78