I'm writing a program where the settings of a spreadsheet-like field of textboxes are changed using two for loops, and I can't for the life of me figure out why it's not working.I have tried declaring the txt variable and name variable in different orders using different methods, but nothing seems to work. With this code, I get the error, "Object reference not set to an instance of an object." Can somebody help me? Thank you.

' For loop repeats for each row
        For i As Integer = 1 To rows Step +1
            ' Creates unicode character code for row naming scheme (Numeric)
            Dim rowsCode As String = "&H" & (rows + 30).ToString()
            ' For loop repeats for each text box in row
            For j As Integer = 1 To columns Step +1
                ' Creates unicode character code for column naming scheme (Alphabetic)
                Dim columnsCode As String = "&H" & (i + 40).ToString()
                ' Creates text box variable and sets settings
                Dim name As String = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
                Dim txt As TextBox = Me.Controls(name)
                txt.Name = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
                txt.Visible = True
                txt.Enabled = True
                txt.BringToFront()
            Next
        Next

Recommended Answers

All 16 Replies

This error typically occurs if you declare an object and try to use it without creating an instance of it (using the "New" key error.

I have a a 3x4 field of them create in the designer, and then rows are added or subtracted using for loops like this:

Private Sub btnAddRow_Click(sender As Object, e As EventArgs) Handles btnAddRow.Click
        ' Adjusts row count
        rows += 1
        ' Creates unicode character code for row naming scheme (Numeric)
        Dim rowsCode As String = "&H" & (rows + 30).ToString()
        ' Calculates the Y of new column
        Dim newY As Integer = ((rows - 1) * 100) + ((rows - 1) * 6) + 39
        ' For loop creates as many new panels, text boxes, and labels as there are coulmns
        For i As Integer = 1 To columns Step +1
            ' Creates unicode character code for column naming scheme (Alphabetic)
            Dim columnsCode As String = "&H" & (i + 40).ToString()
            ' Calculates the X of each new text box
            Dim newX As Integer = ((i - 1) * 200) + ((i - 1) * 6) + 12
            ' Creates new panel
            Dim pnl As New Panel
            pnl.Name = "pnl" & ChrW(columnsCode) & ChrW(rowsCode)
            pnl.Size = New Size(200, 100)
            pnl.Location = New Point(newX, newY)
            pnl.BorderStyle = BorderStyle.FixedSingle
            Me.Controls.Add(pnl)
            ' Creates new label
            Dim lbl As New Label
            lbl.Name = "lbl" & ChrW(columnsCode) & ChrW(rowsCode)
            lbl.Text = "_"
            lbl.Location = New Point(93, 43)
            AddHandler lbl.Click, AddressOf labMouseClick
            AddHandler lbl.DragEnter, AddressOf labDragEnter
            AddHandler lbl.MouseDown, AddressOf labMouseDown
            AddHandler lbl.DragDrop, AddressOf labDragDrop
            AddHandler lbl.MouseUp, AddressOf labMouseUp
            AddHandler lbl.MouseMove, AddressOf labMouseMove
            pnl.Controls.Add(lbl)
            ' Creates new text box
            Dim txt As New TextBox
            txt.Name = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
            txt.Multiline = True
            txt.Size = New Size(192, 92)
            txt.Location = New Point(3, 3)
            pnl.Controls.Add(txt)
            txt.BringToFront()
        Next
        ' Moves buttons to accomodate new row
        Dim newBtnY As Integer = (btnAddRow.Top + 106)
        btnAddRow.Location = New Point(12, newBtnY)
        btnDelRow.Location = New Point(41, newBtnY)
    End Sub

    Private Sub btnDelRow_Click(sender As Object, e As EventArgs) Handles btnDelRow.Click
        ' Creates unicode character code for row naming scheme (Numeric)
        Dim rowsCode As String = "&H" & (rows + 30).ToString()
        ' For loop removes as many panels as there are columns
        For i As Integer = 1 To columns Step +1
            ' Creates unicode character code for column naming scheme (Alphabetic)
            Dim columnsCode As String = "&H" & (i + 40).ToString()
            ' Removes panel
            Dim name As String = "pnl" & ChrW(columnsCode) & ChrW(rowsCode)
            Dim pnl As Panel = Me.Controls(name)
            Me.Controls.Remove(pnl)
        Next
        ' Adjusts row count
        rows -= 1
        ' Moves buttons to accomodate one less row
        Dim newBtnY As Integer = (btnAddRow.Top - 106)
        btnAddRow.Location = New Point(12, newBtnY)
        btnDelRow.Location = New Point(41, newBtnY)
    End Sub

I ran the code and the error is occuring with:

Dim txt As TextBox = Me.Controls(name)

I don't think that you can do that.

The following works for me:

        Dim name As String = "TextBox1"

        Dim columnsCode As Integer = 42
        Dim rowsCode As Integer = 55

        Dim ctrl As Control = Me.Controls(Name)

        Console.WriteLine("TextBox before: " & TextBox1.Name)
        Console.WriteLine()

        If TypeOf ctrl Is System.Windows.Forms.TextBox Then
            ctrl.Name = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
            ctrl.Visible = True
            ctrl.Enabled = True
            ctrl.BringToFront()
            Console.WriteLine("ctrl:  " & ctrl.Name)
        End If

        Console.WriteLine("TextBox after: " & TextBox1.Name)

Placing into your code, it should look like this. This version is untested:

' For loop repeats for each row
For i As Integer = 1 To rows Step +1

   ' Creates unicode character code for row naming scheme (Numeric)
   Dim rowsCode As String = "&H" & (rows + 30).ToString()

   ' For loop repeats for each text box in row
   For j As Integer = 1 To columns Step +1

      ' Creates unicode character code for column naming scheme (Alphabetic)
      Dim columnsCode As String = "&H" & (i + 40).ToString()

      ' Creates text box variable and sets settings

      Dim name As String = "txt" & ChrW(columnsCode) & ChrW(rowsCode)

      '------------------
      'Added
      '------------------
      Dim ctrl As Control = Me.Controls(name)

      If TypeOf ctrl Is System.Windows.Forms.TextBox Then
         ctrl.Name = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
         ctrl.Visible = True
         ctrl.Enabled = True
         ctrl.BringToFront()

         Console.WriteLine("ctrl:  " & ctrl.Name)
      End If

Next
            Next

The "if" statement may be unnecessary, as long as you know the control contains the properties that you are trying to set.

The important part is:

    Dim ctrl As Control = Me.Controls(name)

    ctrl.Name = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
    ctrl.Visible = True
    ctrl.Enabled = True
    ctrl.BringToFront()

    Console.WriteLine("ctrl:  " & ctrl.Name)

Alternatively, you could do the following:

    Dim txt As TextBox
    txt = CType(Me.Controls(name), TextBox)

    txt.Name = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
    txt.Visible = True
    txt.Enabled = True
    txt.BringToFront()

I've tried all the different ways you guys have shown me, and all of them break on the refrence exception the first time a property of the textbox is set or referenced. The error window shows that the textbox variable is not set to anything.

Just because you do

Dim txt As TextBox = Me.Controls(name)

doesn't mean that txt is set to an existing object. If name doesn't exist then txt will be set to nothing and you will get the error. I suspect you are not creating the control name properly. Print out the control name using Debug.WriteLine before you try to retrieve it and that will tell you the name of the (non-existing) control that is causing the error.

Please post the code that you are now using. A screen shot would also be helpful.

I've implemented some checking to see if the control exists (a possible issue that Reverend Jim mentioned above).

Try this:

Dim name As String = "TextBox1"

'check if control with name exists

If Me.Controls.Find(name, True).Count > 0 Then

    Console.WriteLine("Changing name...")

    Dim ctrl As Control = Me.Controls(name)

    'check to see if control is a TextBox
    'if so, change Properties

    If TypeOf ctrl Is System.Windows.Forms.TextBox Then
        ctrl.Name = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
        ctrl.Visible = True
        ctrl.Enabled = True
        ctrl.BringToFront()

        Console.WriteLine("ctrl:  " & ctrl.Name)
    End If

End If

Here are two screenshots of my error screen, including the readout of local variable values. It shows that name is set to txtA1, which definitely exists...

Here is the code I am currently using:

' Code that makes text boxes visible and enabled
        ' For loop repeats for each row
        For i As Integer = 1 To rows Step +1
            ' Creates unicode character code for row naming scheme (Numeric)
            Dim rowsCode As String = "&H" & (i + 30).ToString()
            ' For loop repeats for each text box in row
            For j As Integer = 1 To columns Step +1
                ' Creates unicode character code for column naming scheme (Alphabetic)
                Dim columnsCode As String = "&H" & (j + 40).ToString()
                ' Creates text box variable and sets settings
                Dim name As String = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
                Dim txt As TextBox
                txt = CType(Me.Controls(name), TextBox)
                txt.Name = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
                txt.Visible = True
                txt.Enabled = True
                txt.BringToFront()
            Next
        Next

I suggest you run the program in the debugger and when it breaks on the error, add Me.Controls("txtA1") to the watch list and verify that it exists at that point. If it does, then add Me.Controls(name) to the watchlist as well.

It says that its value is nothing, but I clearly have it created manually in the designer as txtA1.

To help with debugging, you can print out all of the control names on your form using the following sub:

    Private Sub printControls(ByVal ctrlParent As Control)
        Dim ctrl As Control

        For Each ctrl In ctrlParent.Controls

            Console.Write("Parent: " + ctrlParent.Name + "...")
            Console.Write("Child: " + ctrl.Name + "...")
            Console.WriteLine("Type: " + ctrl.GetType().ToString())

            'if control has children
            'recursively call this sub
            If ctrl.HasChildren Then
                printControls(ctrl)
            End If
        Next
    End Sub

Call it like this:

        'Me = this form
        printControls(Me)

Code adapted from here.

Your problem is that txtA1 (and the other textboxes) are not contained in Me.Controls. Each textbox is in a panel and the panels are in Me.Controls. Why not eliminate the panels and just put the textboxes directly into Me.Controls?

By the way, a simpler Sub for displaying the control hierarchy is

Private Sub printControls(ByVal ctrl As Control, indent As Integer)

    Debug.WriteLine(Space(indent) & ctrl.Name)

    For Each child As Control In ctrl.Controls
        printControls(child, indent + 2)
    Next

End Sub

and you call it with

printControls(Me, 0)

I think that Reverend Jim has identified the problem--controls being on a panel.

Try something like the following:

Let's create a sub to rename our controls:

 Private Sub renameControl(ByRef myCtrl As Control,
                          ByVal columnsCode As Integer,
                          ByVal rowsCode As Integer)

 End Sub

To deal with the situation of controls being on a panel, first read the list of controls into a list:

Private Sub renameControl(ByRef myCtrl As Control,
                          ByVal columnsCode As Integer,
                          ByVal rowsCode As Integer)

    'put controls into a list
    Dim ctrlList = Me.Controls.Find(myCtrl.Name, True).ToList()


End Sub

Now, we want to find the control's parent:

    'holds the parent control
    Dim parentCtrl As Control = Nothing

    'find parent for control
    For Each ctrlItem As Control In ctrlList
        parentCtrl = ctrlItem.Parent

        'Console.WriteLine("PARENT: " + ctrlItem.Parent.Name)
    Next

So now we have:

Private Sub renameControl(ByRef myCtrl As Control,
                          ByVal columnsCode As Integer,
                          ByVal rowsCode As Integer)

    'put controls into a list
     Dim ctrlList = Me.Controls.Find(myCtrl.Name, True).ToList()

    'holds the parent control
    Dim parentCtrl As Control = Nothing

    'find parent for control
    For Each ctrlItem As Control In ctrlList
        parentCtrl = ctrlItem.Parent

        'Console.WriteLine("PARENT: " + ctrlItem.Parent.Name)
    Next

End Sub

Next, create a control variable we can use to change the control properties and reference it using it's parent control.

'this will be the control whose
'properties that we will modify
Dim ctrl As Control

'reference control by it's parent control
ctrl = parentCtrl.Controls(myCtrl.Name)

Now we have:

Private Sub renameControl(ByRef myCtrl As Control,
                          ByVal columnsCode As Integer,
                          ByVal rowsCode As Integer)

    'put controls into a list
    Dim ctrlList = Me.Controls.Find(myCtrl.Name, True).ToList()

    'holds the parent control
    Dim parentCtrl As Control = Nothing

    'find parent for control
    For Each ctrlItem As Control In ctrlList
        parentCtrl = ctrlItem.Parent

        'Console.WriteLine("PARENT: " + ctrlItem.Parent.Name)
    Next

    'this will be the control whose
    'properties that we will modify
    Dim ctrl As Control

    'reference control by it's parent control
    ctrl = parentCtrl.Controls(myCtrl.Name)

End Sub

Change the properties:

'check to see if control is a TextBox
'if so, change Properties
If TypeOf ctrl Is System.Windows.Forms.TextBox Then
    ctrl.Name = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
    ctrl.Visible = True
    ctrl.Enabled = True
    ctrl.BringToFront()

    'Console.WriteLine("ctrl:  " & ctrl.Name)
End If

When we are finished, our method should look like this:

Private Sub renameControl(ByRef myCtrl As Control,
                          ByVal columnsCode As Integer,
                          ByVal rowsCode As Integer)

    'put controls into a list      
    Dim ctrlList = Me.Controls.Find(myCtrl.Name, True).ToList()

    'holds the parent control
    Dim parentCtrl As Control = Nothing

    'find parent for control
    For Each ctrlItem As Control In ctrlList
        parentCtrl = ctrlItem.Parent

        'Console.WriteLine("PARENT: " + ctrlItem.Parent.Name)
    Next

    'this will be the control whose
    'properties that we will modify
    Dim ctrl As Control

    'reference control by it's parent control
    ctrl = parentCtrl.Controls(myCtrl.Name)

    'check to see if control is a TextBox
    'if so, change Properties
    If TypeOf ctrl Is System.Windows.Forms.TextBox Then
        ctrl.Name = "txt" & ChrW(columnsCode) & ChrW(rowsCode)
        ctrl.Visible = True
        ctrl.Enabled = True
        ctrl.BringToFront()

        'Console.WriteLine("ctrl:  " & ctrl.Name)
    End If
End Sub

Usage:

renameControl(TextBox1, 42, 55)

The textboxes are in panels for both visual and practical reasons. The overall purpose of this program is that a teacher creates a file and then adjusts the field of textboxes to the number he wants. He then enters terms and their definitions in the textboxes. When he leaves this editing mode, the textboxes are hidden, their values are transferred to the corresponding labels that are created alongside them, which are then randomly arranged on the panel to the right of the screen. Students can then open this file on their computers and attempt to arrange the labels in the correct panels. The program can then check their answers by examining if the labels are in their correct panels. So to recap, the panels provide a visual box once the textboxes visual prperty is set to false, and a functional use for checking the student's answers.

I also apologize for taking so long to respond, school has been keeping me busy.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.