[RESOLVED] Referencing Controls added at Run Time when in Design Time
Hi All,
I am designing a form that has many controls, eg text boxes. When I did the same thing with VB6 I used Control Arrays and it worked fine. It also meant that if I wanted to reference any of the controls they existed on the form already.
Using VB.NET there is no facility for Control Arrays so I add the controls using code to save the painful task of retyping each name etc. However as they are not actually placed on the form until the code is run they cannot be referenced in any instance other than the Public Sub they are created in. I am getting a "[control name] is not a member of the [form name]. It also seams to suck the resources out of the PC whilst loading all the controls.
I would prefer not to have set up all the controls individually.
Any ideas.
Cheers
Ozman.
Re: Referencing Controls added at Run Time when in Design Time
By trying to make your job easier you just made it considerable harder. If you'd done some reading on WHY control arrays, as they existed in VB6, are no longer supported and WHAT you should do to make use of the .NET features that made VB6 control arrays obsolete, then you'd have wasted a lot less time.
Add the controls to the form in the designer. If you want to set the same property for multiple controls then select multiple controls in the designer and then set the desired property in the Properties window. If you want to handle the same event for multiple controls then select multiple controls in the designer, click the Events button at the top of the Properties window and then double-click the desired event. A single method is created to handle the same event for all the controls. If you need to determine which control raised the event at run time you get a reference to it from the 'sender' parameter of the event handler.
If you really do need an array of controls so you can do things like loop through the list at run time and do the same thing to all of them, then you simply create an array of controls in code, the same way you create an array of anything. Arrays of controls are not treated any differently to arrays of other types because they are no different. The actual reason for the design-time support is negated by the .NET event handling mechanism so that design-time support has been removed.
Re: Referencing Controls added at Run Time when in Design Time
What you say about an array of controls and editting is correctand I understand that you can group multiple controls for single events. However if you have say 100 non-enabled textboxes displaying data (and a datagrid is not suitable as because sometimes the data of a single row needs to be split across two rows) how do you access the index feature.
I need to do this to to use one of the data field to determine which textbox the data goes into to ensure it is displayed logically. As the data is imported to the textboxes the event asks to load the text not create an event after something has happened.
The other nice thing about adding the controls via code, as with the VB6 was all positioning of the many controls could be done at run time.
Honestly it just looks like I will have to do alot of typing.
Re: Referencing Controls added at Run Time when in Design Time
There is no index feature. As I said, if you want an array of controls then create an array of controls, exactly as you would create an array of anything.
Given the situation you describe you should also be using a TableLayoutPanel to control the positioning of your TextBoxes. You can set the height and width of rows and columns and all the controls will reposition accordingly.
Re: Referencing Controls added at Run Time when in Design Time
cr*p! some dilly software ran, took over and left off my input focus in such a way as to cause me to post before I was ready! (But I know you can see the original post, so ignore it).
Re: Referencing Controls added at Run Time when in Design Time
As I was saying:
vb.net Code:
Private myCtrlArr() As TextBox = New TextBox(99) {} ' creates an array of textboxes
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim s As String ' assumes your naming scheme is Textbox1, Textbox2, etc
For i As Int32 = 0 To 99 ' your 100 textboxes
s = String.Format("Textbox{0}", i + 1)
myCtrlArr(i) = DirectCast(Me.Controls(s), TextBox) ' import the actual textboxes
' OR, create your own:
' myCtrlArr(i) = New TextBox '
Next
' (if you created new textboxes):
' Me.Controls.AddRange(myCtrlArr)
' add code here to handle the placement of your new textboxes, maybe into layout table as suggested
' you now have your control array
' knock yourself out...
End Sub
Re: Referencing Controls added at Run Time when in Design Time
Thanks for that. But how do I reference this Control Array from other forms. I am running into the same problem as when I added the new controls at runtime. There does not appear to be a reference to the array from outside that form.
Re: Referencing Controls added at Run Time when in Design Time
If you use a TableLayoutPanel you can refer to them by there grid coordinates too, so an array may be completely unnecessary.
Re: Referencing Controls added at Run Time when in Design Time
Something like this kind of thing would do:
Code:
Dim MyTextBoxes() As TextBox
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ReDim MyTextBoxes(100) 'Let's assume we want 100 textboxes
For i = 1 To 100
MyTextBoxes(i) = New TextBox 'Create new instance of textbox
MyTextBoxes(i).Name = "MyTextBoxes" & i 'Whatever name we want to keep (unique)
MyTextBoxes(i).Left = 50 'set the properties like left, top, width, height, text etc.
MyTextBoxes(i).Top = 50 * i
AddHandler MyTextBoxes(i).Click, AddressOf MyTextBoxes_Click 'Add event handler(s)
Me.Controls.Add(MyTextBoxes(i)) 'Add it to the form
Next
End Sub
Private Sub MyTextBoxes_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim t As TextBox = CType(sender, TextBox)
MsgBox("I am " & t.Name)
End Sub
EDIT: To access it from outside, just make the declaration of MyTextBoxes PUBLIC.
Code:
Public MyTextBoxes() As TextBox
Pradeep :)
Re: Referencing Controls added at Run Time when in Design Time
bigMeUp,
That code does the job. Would there be some way of saving it and other Arrays in a separate Class or Module and then calling them when required?
I have tried it but keep running into a NullReferenceException was unhandled error.
Re: Referencing Controls added at Run Time when in Design Time
Why would you want to? What do you hope to gain by doing so?
I should also point out that Pradeep's code has created an array with 101 elements. It should be 99 so the 100 elements are at indexes 0 to 99.
Re: Referencing Controls added at Run Time when in Design Time
As I mentioned above. If the controls are called by a subroutine outside the actual form the NullReferenceException was unhandled error occurs.
It is the same as when I create my controls at runtime. I wish to have code that can be accessed across forms. Pretty normal and it works with the VB6 program. I like to keep code tidy by keeping all related items together and not typing any code more than once. If there is no way of doing this every Array of Controls will have to keyed in each relevant form.
Re: Referencing Controls added at Run Time when in Design Time
If you want to do things the "correct" way then you won't expose any of your controls publicly. If something on the form needs to be manipulated from the outside you declare a public method that can be called from the outside and then you perform the manipulation in that method, within the form.
Also, your explanation makes no sense to me. If you have two different forms with two different arrays of controls then how can "saving it and other Arrays in a separate Class or Module" reduce the amount of code you type? Two arrays is two arrays however you look at it. If you want to "keep code tidy by keeping all related items together" then you'll keep all code relating to the controls on a particular form within that form. That's called encapsualtion and is a basic principle of OOP. If you have utility functions that may need to be called in various places on various arrays then it would be appropriate to put those in their own class or module, but then the form would call those methods and pass the control arrays when and as needed.
Re: Referencing Controls added at Run Time when in Design Time
Quote:
Originally Posted by jmcilhinney
...
I should also point out that Pradeep's code has created an array with 101 elements. It should be 99 so the 100 elements are at indexes 0 to 99.
Correct.
I come from VB background and have a habit of keeping base 1. So in .net I just ignore the 0th array slot. That way we can keep how we think logically - 100 elements = 1, 2, 3, 4, ... 100.
So it's 100 elements on the form anyway (0th is Nothing :D)
Here's the corrected code:
Code:
Dim MyTextBoxes() As TextBox
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ReDim MyTextBoxes(99) 'Let's assume we want 100 textboxes
For i = 0 To 99
MyTextBoxes(i) = New TextBox 'Create new instance of textbox
MyTextBoxes(i).Name = "MyTextBoxes" & i 'Whatever name we want to keep (unique)
MyTextBoxes(i).Left = 50 'set the properties like left, top, width, height, text etc.
MyTextBoxes(i).Top = 50 * i
AddHandler MyTextBoxes(i).Click, AddressOf MyTextBoxes_Click 'Add event handler(s)
Me.Controls.Add(MyTextBoxes(i)) 'Add it to the form
Next
End Sub
Private Sub MyTextBoxes_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim t As TextBox = CType(sender, TextBox)
MsgBox("I am " & t.Name)
End Sub
Re: Referencing Controls added at Run Time when in Design Time
???
I not trying to do as you say. All I want is a form with an array of controls on it. The program uses numerous forms which can manipulate the info on a main in different ways. Pretty normal. For ease of an explanation, Data can be loaded into the Array of Controls, lets say text boxes. One form does task A the other form task B. But both forms access that same data contained in the Array of Controls.
In VB6 and the indexing this was a piece of cake.
code in Form2 or Form3 wants to use controls in Form1
Code:
i = 1 to 10
form1.textbox(i).text= whatever
next i
Any code from any form can use the same thing. That is what I am asking for HELP with. Yes I can make an Array of Controls but how do I access the Array from other form.
Both the soultions above work as does my original solution until I want to access the info in the textboxes from another form.
From your explanation if I have three forms wanting to access the textboxes I would need three separate arrays to access the same textboxes. Which is what I am trying to avoid. As well as the fact that I can only access the controls across forms individually.
As I said worked in VB6 so there must be a way to do it here.
Re: Referencing Controls added at Run Time when in Design Time
Hi there!
Pradeep's code is great for adding the textboxes.
As I understand it, it is usually better not to reference controls on a form directly from outside.
Assuming that you want to simply get that text from those textboxes you could add a string array as a property to the form.
Here is suggestion how you could do it. Not sure if that is good practice but it certainly works :). Any comments are welcome.
(You will need 2 forms. Form1 needs 2 buttons and a multiline textbox with vertical scrollbar, Form2 can be empty. I added '\\ in front and after my additions to pradeep's code)
Form2
Code:
Public Class Form2
Dim MyTextBoxes() As TextBox
'\\
Private propTextboxText() As String
Friend ReadOnly Property MyText() As String()
Get
Return propTextboxText
End Get
End Property
'\\
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim i As Integer
ReDim MyTextBoxes(99) 'Let's assume we want 100 textboxes
'\\
ReDim propTextboxText(99)
'\\
For i = 0 To 99
MyTextBoxes(i) = New TextBox 'Create new instance of textbox
MyTextBoxes(i).Name = "MyTextBoxes" & i 'Whatever name we want to keep (unique)
MyTextBoxes(i).Left = 50 'set the properties like left, top, width, height, text etc.
MyTextBoxes(i).Top = 50 * i
AddHandler MyTextBoxes(i).Click, AddressOf MyTextBoxes_Click 'Add event handler(s)
'\\
MyTextBoxes(i).Tag = i 'Add a tag
AddHandler MyTextBoxes(i).LostFocus, AddressOf MyTextBoxes_LostFocus 'Add event handler to store text
'\\
Me.Controls.Add(MyTextBoxes(i)) 'Add it to the form
Next
End Sub
Private Sub MyTextBoxes_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim t As TextBox = CType(sender, TextBox)
MsgBox("I am " & t.Name)
End Sub
'\\
Private Sub MyTextBoxes_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs)
Dim t As TextBox = CType(sender, TextBox)
propTextboxText(t.Tag) = t.Text
End Sub
'\\
End Class
Form1
Code:
Public Class Form1
Dim frm As Form2
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
frm = New Form2
frm.Show()
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim str As String
Dim intC1 As Integer
Dim intUB1 As Integer
intUB1 = frm.MyText.GetUpperBound(0)
For intC1 = 0 To intUB1
str = str & "Textbox " & CStr(intC1) & " text: " & frm.MyText(intC1) & vbNewLine
Next intC1
Me.TextBox1.Text = str
End Sub
End Class
regards
BManke
P.S.: As you can see from my code you can also abuse the .tag property and use it like the index of VB 6 days
1 Attachment(s)
Re: Referencing Controls added at Run Time when in Design Time
Quote:
Originally Posted by OZMan
???
...
In VB6 and the indexing this was a piece of cake.
code in Form2 or Form3 wants to use controls in Form1
Code:
i = 1 to 10
form1.textbox(i).text= whatever
next i
Any code from any form can use the same thing. That is what I am asking for HELP with. Yes I can make an Array of Controls but how do I access the Array from other form.
...
As I said worked in VB6 so there must be a way to do it here.
In .NET it's even easier. ;)
Only the thing that you should understand what you are coding and what effects it will have. :D
Though this is not the standard way, this will work just the way you want:
This is Form2 code. (I assume you have a button "Button1" which when clicked will fill Form1 textboxes)
Code:
Public Class Form2
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim f As New Form1
f.Show()
f.MyTextBoxes(1).Text = "filled from form 2"
End Sub
End Class
And this is Form1 code:
Code:
Public Class Form1
Public MyTextBoxes() As TextBox
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ReDim MyTextBoxes(99) 'Let's assume we want 100 textboxes
For i = 0 To 99
MyTextBoxes(i) = New TextBox 'Create new instance of textbox
MyTextBoxes(i).Name = "MyTextBoxes" & i 'Whatever name we want to keep (unique)
MyTextBoxes(i).Left = 50 'set the properties like left, top, width, height, text etc.
MyTextBoxes(i).Top = 50 * i
AddHandler MyTextBoxes(i).Click, AddressOf MyTextBoxes_Click 'Add event handler(s)
Me.Controls.Add(MyTextBoxes(i)) 'Add it to the form
Next
End Sub
Private Sub MyTextBoxes_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim t As TextBox = CType(sender, TextBox)
MsgBox("I am " & t.Name)
End Sub
End Class
The exception you are getting is most probably because you are trying to use the textboxes array before it is even initialized.
Pradeep :)
Re: [RESOLVED] Referencing Controls added at Run Time when in Design Time
Thanks for that.
The line Dim f As New Form1 appears to have done the trick.
As usual it was something small causing a large problem.
Thanks to all who have helped.