adding multiple textbox .net - vb.net

What i want is when i input a number in texbox1.text like for example i enter 3 it should show 3 textbox but i always get an error. and also i have to save it in database but i dont know how. Help Please..
Private boxes(TextBox1.text) As TextBox
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim newbox As TextBox
For i As Integer = 1 To TextBox1.Text
newbox = New TextBox
newbox.Size = New Drawing.Size(575, 35)
newbox.Location = New Point(10, 10 + 35 * (i - 1))
newbox.Name = "TextBox" & i
newbox.Text = newbox.Name
'connect it to a handler, save a reference to the array and add it to the form controls
AddHandler newbox.TextChanged, AddressOf TextBox_TextChanged
boxes(i) = newbox
Me.Controls.Add(newbox)
Next
End Sub

OK. The error I get when I try to run your code is :-
An unhandled exception of type 'System.InvalidCastException' occurred in Microsoft.VisualBasic.dll
Additional information: Conversion from string "" to type 'Integer' is not valid.`
This is because you're trying to start a loop using a string as the termination index for the loop. Try using
For i As Integer = 1 To Val(TextBox1.Text)
your next problem will depend on how you've declared boxes. If you have declared it like this ..
Dim boxes() As TextBox
You'll end up with a Null reference exception because when you declared boxes, you didnt supply any elements. To remedy this you'll need to add this just before your loop ..
ReDim Preserve boxes(Val(TextBox1.Text))
If boxes is a list.. and to be honest .. thats a better choice than an array, instead of the above line you'll need to change
boxes(i) = newbox
to
boxes.Add(newbox)
You might also need to change other code associated with boxes, but the work will be worth it.
Your biggest problem is that you're trying to get a value from a TextBox that hasn't even appeared yet. You've put your code inside the form's load event. It really needs to be in a separate method. Oh and rather than use the TextBox.changed event you should use a button control to execute the method. Otherwise it's too easy for someone to change the number in the textbox. With your code, each time the textbox is changed (deleting a digit or adding another digit), more TextBoxes will be added and you could end up with lots of them.
So possible final code should look like ..
Public Class Form1
Dim boxes As New List(Of TextBox)
Private Sub Addbuttons(buttonCount As Integer)
Dim newbox As TextBox
For i As Integer = 1 To buttonCount
newbox = New TextBox
newbox.Size = New Drawing.Size(575, 35)
newbox.Location = New Drawing.Point(10, 10 + 35 * (i - 1))
newbox.Name = "TextBox" & i
newbox.Text = newbox.Name
'connect it to a handler, save a reference to the array and add it to the form controls
boxes.Add(newbox)
Me.Controls.Add(newbox)
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Addbuttons(Val(TextBox1.Text))
End Sub
End Class

Related

How can I use a variable to reference a textbox?

I'm new to visual basic and programming in general, but I'm trying to make a statistic counter sort of program. I'm trying to use a variable to reference a textbox, for example, k_kills(i) = txtKills(i).Text. This doesn't work, however, so I then tried the following:
For i = 0 To 8
Dim tempBox As TextBox
Dim tempName As String = "txtKills" & i.ToString
tempBox = Me.Controls.Item(tempName)
k_kills(i) = tempBox.Text
Next
This also doesn't work and spits out an error each time saying that 'tempBox was Nothing'.
Can anyone tell me if I can make this work?
Thanks.
You will need to find the control in some collection. By default the control would exist in its parent's Controls property and since you're trying to get the control by its name then you could use ControlCollection's Find method. If you can guarantee that the control's parent is the Form then you'd call:
Dim tempBox As TextBox = DirectCast(Me.Controls.Find(tempName, False), TextBox)
But if there is the possibility that the control's parent is something other than the Form then you'd call:
Dim tempBox As TextBox = DirectCast(Me.Controls.Find(tempName, True), TextBox)
The first would execute slightly quicker because it only iterates over the current ControlCollection whereas the second could take longer because if it cannot find the control in the current ControlCollection then it starts to iterate over the child controls as well.
Assuming the controls are all in Form as parent and they all start with txtKills...
If you are going to use these text boxes as a group for several actions you may want to build an array or list of TextBox.
Dim Kills(7) As TextBox
Private Sub CreateTextBoxArray()
Dim index As Integer
For Each ctrl As Control In Controls
If ctrl.Name.StartsWith("txtKills") Then
Kills(index) = DirectCast(ctrl, TextBox)
index += 1
End If
Next
End Sub
Private Sub ClearKillTextBoxes()
For Each t In Kills
t.Clear()
Next
End Sub
Private Function GetTextFromKillBoxes() As List(Of String)
Dim lst As New List(Of String)
For Each t In Kills
lst.Add(t.Text)
Next
Return lst
End Function
After Mary's comment I edit my answer to add this line --> My code does not work if Option Strict is On and 'For' starting in 0 or 1 or any number and txtKills[X] exists.
This was my previous answer and I don't know if I have to delete or not:
Your code works fine but I think you have an error because your For starts in 0 and you don't have any "txtKills0". I've tested it now:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim k_kills(10) As String '<< Ignore the length
For i = 1 To 7
Dim tempBox As TextBox
Dim tempName As String = "txtKills" & i.ToString
tempBox = Me.Controls.Item(tempName)
k_kills(i) = tempBox.Text
MsgBox(k_kills(i))
Next
End Sub

How to filter unbound datagridview with textbox vb.net?

I'm a complete rookie. I learned so much from here but this one I can't find the answer to. I'm using Visual Studio Pro 2015.
I have a windows form application that has a single column datagridview that is populated by reading a textfile, line by line at runtime. Each time the contents of the textfile will be different.
I want the user to be able to filter the list in the datagridview by entering characters in a textbox. The data is not "bound" to the datagridview, because at this point I don't know if that is necessary, and I don't completely understand it.
This is the code that I have for loading the datagridview, and the textbox is called txtFilter.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'read all lines from the file into a string array (one line per string)
Dim lines() As String = My.Computer.FileSystem.ReadAllText("c:\list_in.txt").Replace(vbLf, "").Split(vbCr)
Dim dgrow As DataGridViewRow
Dim dgcell As DataGridViewCell
'insert each line of input into a row in the datagrid
For Each line As String In lines
dgrow = New DataGridViewRow
dgcell = New DataGridViewTextBoxCell
If line <> "" Then
dgcell.Value = line
dgrow.Cells.Add(dgcell)
DataGridView1.Rows.Add(dgrow)
End If
Next
DataGridView1.Columns("ObjectName").ReadOnly = True
DataGridView1.ClearSelection()
End Sub
Edit:
Looking at your solution, I would advise you execute Dim lines() As String = My.Computer.FileSystem.ReadAllText("c:\list_in.txt").Replace(vbLf, "").Split(vbCr) outside of the txtFilter_TextChanged sub, as otherwise you are importing the entire list every time the user enters a key, which is unnecessary. If the list may change while the user is using the program, I'd instead recommend adding a 'refresh' button, especially if your text file could be a long one.
You also added a couple lines of code to remove the sound when the user presses the Enter key. If the user is expected to press the enter key to search, then you don't need to update the DataGridView every time the user enters a new character in the textbox. This would be easier on memory, and again very beneficial if you have a large text file.
I'm sure there's an easier way, but here's my approach.
Private Sub txtFilter_TextChanged(sender As Object, e As EventArgs) Handles txtFilter.TextChanged
Dim searchedlines(-1) As String 'create an array to fill with terms that match our search
If txtFilter.Text = Nothing Then
datapopulate(lines) 'just populate the datagridview with our text file array
Else
For Each line In lines
If line Like "*" & txtFilter.Text & "*" Then 'check if anything in our search matches any of our terms
ReDim Preserve searchedlines(UBound(searchedlines) + 1) 'resize the array to fit our needs
searchedlines(UBound(searchedlines)) = line 'add the matched line to our array
End If
Next
datapopulate(searchedlines) 'populate the datagrid with our matched terms array
End If
End Sub
Private Sub datapopulate(ByVal mylist)
Dim dgrow As DataGridViewRow
Dim dgcell As DataGridViewCell
DataGridView1.Rows.Clear() 'clear the grid
For Each line As String In mylist 'do the same thing here that we did on form load
dgrow = New DataGridViewRow
dgcell = New DataGridViewTextBoxCell
dgcell.Value = line
dgrow.Cells.Add(dgcell)
DataGridView1.Rows.Add(dgrow)
Next
End Sub
What I did is created a sub that handles whenever the text in txtFilter is changed. Alternatively, you could run that code in a sub that handles a button click. Given that, from what I know, ReDim can be a costly item in terms of memory usage, if your text document was hundreds of lines long, you might want it on a button click instead. You could probably use a list, but I haven't played around enough to know how to go about doing that.
An important note: in order for the sub txtFilter_TextChanged to be able to see lines(), I defined it outside of a sub but inside of your main class, so that all subs could access it, like so:
Public Class Form1
Dim lines() As String = My.Computer.FileSystem.ReadAllText("c:\list_in.txt").Replace(vbLf, "").Split(vbCr)
'...subs here...
End Class
I hope this helps you get started!
I have a solution working. Thank you very much.
Private Sub txtFilter_TextChanged(sender As Object, e As EventArgs) Handles txtFilter.TextChanged
'read all lines from the file into a string array (one line per string)
Dim lines() As String = My.Computer.FileSystem.ReadAllText("c:\list_in.txt").Replace(vbLf, "").Split(vbCr)
Dim dgrow As DataGridViewRow
Dim dgcell As DataGridViewCell
DataGridView1.Rows.Clear()
'insert each line of input into a row in the datagrid
For Each line As String In lines
dgrow = New DataGridViewRow
dgcell = New DataGridViewTextBoxCell
If line.Contains(txtFilter.Text) Then
dgcell.Value = line
dgrow.Cells.Add(dgcell)
DataGridView1.Rows.Add(dgrow)
End If
Next
DataGridView1.Columns("ObjectName").ReadOnly = True
DataGridView1.ClearSelection()
End Sub
And I also found this to eliminate the bell from ringing when the user pressed the enter key when entering the filter text.
Private Sub txtFilter_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtFilter.KeyPress
' this keeps the bell from ringing when the user presses the 'enter' key
If Asc(e.KeyChar) = 13 Then
e.Handled = True
End If
End Sub

Data doesn't display when working with multiple forms

I'm new to VB.NET and have been struggling all afternoon with something. I've found similar questions on the forum but none of them seemed to describe my problem exactly. I'm fairly sure that I'm missing something very basic.
I have made a main form which currently holds only one button which purpose is to open up a second form and close the main form. Based on the settings the user will select on the 2nd form the first form might have to be adapted to match with the new settings. But the problem occurs even before that.
The 'settings' form has 15 textboxes which I drew onto the form in development mode. They are called ID1, ID2,..,ID15. The values which I want to display in there are saved in an array:
Dim ids(15) as integer
Next, I created a module to simulate what you could call a control array as I used to use them in VB6.
Public sources() As TextBox = [frmSettings.ID1, frmSettings.ID2, //and so on
I did this to be able to iterate through all the 15 textboxes:
For i = 0 To 14
Sources(i).Text = ids(i + 1)
Next
Then I added on the main form this code to the Button1_Click() event:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
frmSettings.Show()
Me.Close()
End Sub
I did the same thing for the 'exit ' button on the frmSettings form.
This seems to work, but only once. I launch the application, push the button and frmSettings pops up and shows all the values from the array in the textboxes. When I push the 'close' button, I return to the main page.
So far so good, but if I try to return to frmSettings a second time, all the textboxes remain blank as if the code I added to the form never gets executed.
Any help would be greatly appreciated!
First, make sure the array that holds your data is accessible to both forms:
Module Module1
Public ids(15) As Integer
End Module
There should not be a declaration for "ids" in either form.
Next, make frmSettings itself responsible for loading and saving the data:
Public Class frmSettings
Private Sub frmSettings_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim matches() As Control
For i As Integer = 0 To 14
matches = Me.Controls.Find("ID" & (i + 1), True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is TextBox Then
Dim TB As TextBox = DirectCast(matches(0), TextBox)
TB.Text = ids(i)
End If
Next
End Sub
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
Dim valid As Boolean = True
Dim matches() As Control
For i As Integer = 0 To 14
matches = Me.Controls.Find("ID" & (i + 1), True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is TextBox Then
Dim TB As TextBox = DirectCast(matches(0), TextBox)
Dim value As Integer
If Integer.TryParse(TB.Text, value) Then
ids(i) = value
Else
MessageBox.Show(TB.Name & ": " & TB.Text, "Invalid Value", MessageBoxButtons.OK, MessageBoxIcon.Warning)
valid = False
End If
End If
Next
If valid Then
Me.Close()
End If
End Sub
End Class

How to manage dynamically created controls in VB.NET?

I just understand how to make controls dynamically in VB.NET (I mean, only part of adding a new one)
But, unlike VB6, it seems hard to handle those dynamic things.
When I click the DONE button, I want to make an array filled with the text of textboxes.
At the same time, I want to make a Delete button that removes the button itself and the textbox in the same line.
Is there any simple method or an sample code for this?
Thank you!
Drop a TableLayoutPanel on your form, called pnlLayout, and also the Add button called btnAdd. Configure TableLayoutPanel to have two columns, adjust column width as needed.
Paste below code into your form:
Public Class Form1
Dim deleteButtons As List(Of Button)
Dim textBoxes As List(Of TextBox)
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
deleteButtons = New List(Of Button)
textBoxes = New List(Of TextBox)
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim elementCount As Integer = deleteButtons.Count
Dim txt As New TextBox
txt.Width = 100
txt.Height = 20
textBoxes.Add(txt)
Dim btn As New Button
btn.Width = 100
btn.Height = 20
btn.Text = "Delete " & elementCount.ToString
AddHandler btn.Click, AddressOf btnDelete
deleteButtons.Add(btn)
pnlLayout.SetCellPosition(txt, New TableLayoutPanelCellPosition(0, elementCount))
pnlLayout.SetCellPosition(btn, New TableLayoutPanelCellPosition(1, elementCount))
pnlLayout.Controls.Add(btn)
pnlLayout.Controls.Add(txt)
End Sub
Private Sub btnDelete(sender As Object, e As EventArgs)
Dim senderButton As Button = DirectCast(sender, Button)
Dim txt As TextBox = textBoxes(deleteButtons.IndexOf(senderButton))
pnlLayout.Controls.Remove(senderButton)
pnlLayout.Controls.Remove(txt)
End Sub
End Class
By default, it will have no textboxes and no Delete buttons, you can add as many rows of "Textbox + Delete button" as you want. When you press Delete, the row will be removed (and everything shifted to accommodate the empty space).
For the textbox'ex part:
Dim strcol() As String = {TextBox2.Text, TextBox3.Text}
For Each strtxt In strcol
MessageBox.Show(strtxt)
Next
It really depends on your code, but, if you have their name use this to delete the buttons &/ textbox'es:
For i As Integer = Me.Controls.Count - 1 To 0 Step -1
If TypeOf Me.Controls(i) Is TextBox Then
If Me.Controls(i).Name = "TextBox2" Then
Me.Controls.RemoveAt(i)
End If
End If
If TypeOf Me.Controls(i) Is Button Then
If Me.Controls(i).Name = "Button3" Then
Me.Controls.RemoveAt(i)
End If
End If
Next
But it depends on your code...

How to create Control Arrays in VB .NET

In VB6 there is a feature called Control Arrays, where you name controls the same name and provide them an index value. This allows you to set a value by looping through the controls and setting each value. In VB .NET I can't create a control array could someone provide me with a similar solution.
Here is a sample I wrote for something else that shows how to do something similar and shows how to do the handler as well. This makes a 10x10 grid of buttons that turn red when you click them.
Dim IsCreated(99) As Boolean
Dim Buttons As New Dictionary(Of String, Button)
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
For i As Integer = 0 To 99
Dim B As New Button
Me.Controls.Add(B)
B.Height = 30
B.Width = 40
B.Left = (i Mod 10) * 41
B.Top = (i \ 10) * 31
B.Text = Chr((i \ 10) + Asc("A")) & i Mod 10 + 1
Buttons.Add(B.Text, B)
B.Tag = i
AddHandler B.Click, AddressOf Button_Click
Next
End Sub
Private Sub Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim B As Button = sender
IsCreated(B.Tag) = True
B.BackColor = Color.Red
End Sub
Avoid using the proposed iteration approaches, you'll get a fairly random collection of controls unless your form is very simple. Simply declare the control array in your code and initialize it in the form constructor. Like this:
Public Class Form1
Private OrderNumbers() As TextBox
Public Sub New()
InitializeComponent()
OrderNumbers = New TextBox() {TextBox1, TextBox2}
End Sub
End Class
You can now treat OrderNumbers just like you could in VB6.
Maybe this is simpler. To create a control array, I put the control array declaration in a module. For example, if I have a Form with three TextBoxes and I want the TextBoxes to be part of a control array called 'mytext', I declare my control array in a module as follows:
Module Module1
Public mytext() As TextBox = {Form1.TextBox1, Form1.TextBox2, Form1.TextBox3}
End Module
And, I use the TextBoxes from the control array as follows:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
mytext(0).Text = "Hello"
mytext(1).Text = "Hi"
mytext(2).Text = "There"
End Sub
End Class
You can even loop through the control array, like you could in VB6:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
For i As Integer = 0 To 2
mytext(i).Text = i + 1
Next
End Sub
End Class
The beauty of using a module is that the TextBoxes do not even need to be in the same form.
With Winforms, you could do this:
myForm.Controls _
.OfType(Of TextBox) _
.OrderBy(Function(c) c.Name) _
.Where(Function(c) c.Name.StartsWith("somePrefix")) _
.ToArray()
On your form you would name your textboxes somePrefix1, somePrefix2, etc.
Here is an old article but it could give you more information. The top method is super easy.
Your Form, or PanelControl, or anything else that can contain child controls will have a Property called Controls.
You can loop through all of the text boxes in a control by using
'Create a List of TextBoxes, like an Array but better
Dim myTextBoxControls As New List
For Each uxControl As UserControl in MyFormName.Controls
If TypeOf(uControl) is TextBox
myTextBoxControls.Add(uControl)
End IF
Next
Now you have your iterate-able collection you can work with.
You can access a TextBoxes value with the EditValue property.
After looking at what you're trying to do a little further.
You probably want to name all of your controls with a Prefix, let's say abc for now.
For Each uxControl As UserControl in MyFormName.Controls
If TypeOf(uControl) is TextBox Then
Dim tbControl As TextBox = DirectCast(uControl, TextBox)
If tbControl.Name.StartsWith("abc") Then
tbControl.EditValue = "the Value you want to initialize"
End If
End If
Next
So this is one of the features that did not make the transition to VB.NET -- exactly :-( However, you can accomplish much of what you would have done in VB6 with two different mechanisms in .NET: Looping through the controls collection and handling control events.
Looping Through the Controls Collection
In VB.NET every form and control container has a controls collection. This is a collection that you can loop through and then do an operation on the control like set the value.
Dim myTxt As TextBox
For Each ctl As Control In Me.Controls
If TypeOf ctl Is TextBox Then
myTxt = CType(ctl, TextBox)
myTxt.Text = "something"
End If
Next
In this code sample you iterate over the controls collection testing the type of the returned object. If you find a textbox, cast it to a textbox and then do something with it.
Handling Control Events
You can also handle events over multiple controls with one event handler like you would have using the control array in VB6. To do this you will use the Handles keyword.
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged, TextBox2.TextChanged, TextBox3.TextChanged
Dim myTxt As TextBox = CType(sender, TextBox)
MessageBox.Show(myTxt.Text)
End Sub
The key here is the Handles keyword on the end of the event handler. You separate out the various controls that you want to handle and the event by using a comma. Make sure that you are handling controls that have the same event declaration. If you ever wondered what sender was for on every event well here's one of the uses for it. Cast the sender argument to the type of control that you are working with and assign it to a local variable. You will then be able to access and manipulate the control that fired the event just like you would have in VB6 if you specified and index to the array.
Using these two techniques you can replicate the functionality of control arrays in VB6. Good luck.
Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
Dim a() As Control = GetControls("textbox")
For Each c As TextBox In a
c.Text = c.Name
Next
End Sub
Private Function GetControls(typeOfControl As String) As Control()
Dim allControls As New List(Of Control)
'this loop will get all the controls on the form
'no matter what the level of container nesting
'thanks to jmcilhinney at vbforums
Dim ctl As Control = Me.GetNextControl(Me, True)
Do Until ctl Is Nothing
allControls.Add(ctl)
ctl = Me.GetNextControl(ctl, True)
Loop
'now return the controls you want
Return allControls.OrderBy(Function(c) c.Name). _
Where( _
Function(c) (c.GetType.ToString.ToLower.Contains(typeOfControl.ToLower) AndAlso _
c.Name.Contains("Box")) _
).ToArray()
End Function