How can I use a variable to reference a textbox? - vb.net

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

Related

Storing text box input into an array and displaying it on to a list box in visual basic

What i need to do is take input 10 times from a text box, store it in an array and then display the array onto a list box.
I came up with this for loop but it doesn't work, all it does is display the first input and then the rest are just blank:
For i As Integer = 0 To 9
ArrNames(i) = txtUserInput.Text
txtUserInput.Clear()
Next i
and i have a different button to display the array and i used this:
lstDisplay.DataSource = ArrNames
can anyone help me? iv'e looked everywhere and nothing worked for me
Edit 1:
So i changed it a lot and came up with this:
Dim I As Integer
If sender Is btnEnter Then
I = I + 1
End If
ArrNames(I) = txtUserInput.Text
txtUserInput.Clear()
is what it does is if the button is pressed it increases I by one which makes it so the input goes to the right index right?
but now that i make this it stopped displaying anything at all so this:
Private Sub btnShow_Click(sender As Object, e As EventArgs) Handles btnShow.Click
lstDisplay.DataSource = ArrNames
stopped working
Hopefully that I variable is declared at class level in the same place as the array.
To force the ListBox to refresh you have to set the .DataSource to Nothing and then back to your array again:
Public Class Form1
Private I As Integer
Private ArrNames(9) As String
Private Sub btnAddName_Click(sender As Object, e As EventArgs) Handles btnAddName.Click
If I < ArrNames.Length Then
If txtUserInput.Text.Trim.Length > 0 Then
ArrNames(I) = txtUserInput.Text
I = I + 1
lstDisplay.DataSource = Nothing
lstDisplay.DataSource = ArrNames
txtUserInput.Clear()
txtUserInput.Focus()
Else
MessageBox.Show("Enter a name first!")
End If
Else
MessageBox.Show("The array is full!")
End If
End Sub
End Class
I would first recommend you to use typed Lists instead of using the old fashioned array (discussions incoming.. but..).
You can also make use of the nice feature of Enumerable.Range().
I don't have my editor right now but it should look like:
Dim list = new List(Of string)
For i In Enumerable.Range(1, 10)
list.Add(txtUserInput.Text)
Next
txtUserInput.Clear()
lstDisplay.DataSource = list
If you plan to modify your list afterwards and e.g. keep it on class scope, then you should use a BindingList(Of String) which supports notifying about changes.
Edit 1:
You are calling txtUserInput.Clear() inside the loop after the first time your input has been received from the textbox. That means in each following iteration the textbox is cleared.

is there any way to simplify this code? vb.net [duplicate]

i have been created buttons and textboxs by coding in next loop,
the result
'T(x).Name = "text_1"
'T(x).Name = "text_2"
'T(x).Name = "text_3"
'....
'B(x).Name = "button_1"
'B(x).Name = "button_2"
'B(x).Name = "button_3"
'...
and i want to get textbox property whene i click the button,
i can get button property when click like button_1.Name.ToString
but i cant get the text_1,2,3 .... property.
i do some trick by split function button_1.Name.ToString and get the last number
and add it to the textbox name like "text_" & button_1.Name.ToString but i can't convert this string to object.
Update
Here's the code I'm using to load the controls in the loop:
C_A_TEXT(x) = New TextBox()
C_A_TEXT(x).Dock = System.Windows.Forms.DockStyle.Fill
C_A_TEXT(x).Location = New System.Drawing.Point(270, 5)
C_A_TEXT(x).Margin = New System.Windows.Forms.Padding(0)
C_A_TEXT(x).Size = New System.Drawing.Size(70, 27)
C_A_TEXT(x).TabIndex = 5
C_A_TEXT(x).Name = "NEW_RECHARGE_COUNT_TEXT_" & x
Update 2
Here's some more code:
AddHandler C_A_BUTTONS(x).Click, AddressOf C_A_BUTTON
Private Sub C_A_BUTTON(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim thisButton As Button = sender Dim A = CType(Me.Controls("NEW_RECHARGE_COUNT_TEXT_1"), TextBox)
MsgBox(A.Text.ToString) 'Error!
End Sub
You can access the controls by name via the Form.Controls property, for instance:
Dim text1 As TextBox = CType(Me.Controls("text_1"), TextBox)
As a quick useful tip to note, you don't seem to have to specify the type of control within the CType statement for purposes of accessing a control on your form. I came across this when trying to access multiple types of form controls, such as buttons and textboxes, all with the same line of code.
CType(Controls("NAME_OF_CONTROL"), Control)
Note that, rather than specifying exactly what type of control, such as 'TextBox' or 'Button', you simply state 'Control'. This allows you to universally change any type of control, without needing to specify its type.
I couldn't find this anywhere else, so I thought I'd share it!
Below is the code.
Dim oObj As Object = Me.Controls.Find("control name", True).FirstOrDefault()
Obj.Property = Value
I hope it helps.
Dim sometext As TextBox = CType(Me.Controls("sometext "), TextBox)
The title of the thread and your description of the problem at hand seem a little different from each other.
To answer your title (to find a control by its name) use the following:
Dim myControlToFind = LayoutRoot.FindName("NAMEOFCONTROL")
More information on this method can be found here .
To answer the description of your issue as (to access a code generated control after it is clicked) do the following:
In the loop where you are creating the control(s) add the following handler
Addhandler YOURCONTROL.Clicked, AddressOf Textbox_Clicked
...and then this will handle the click event
Private Sub Textbox_Clicked(sender as object, e as RoutedEventArgs)
Dim tbClicked = Ctype(sender, TextBox)
'You can now access any of the properties of the textbox, for example
Dim txt as String = tbClicked.Text
Dim name as String = tbClicked.Name
Dim height as Double = tbClicked.Height
End Sub
None of the above worked for me. This does:
Dim selVal As String = CType(Form.FindControl(myListName), DropDownList).SelectedValue

adding multiple textbox .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

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

Deleting controls each time ShowDialog is called

I have a form that I display exclusively with the ShowDialog method. In the Form_Shown event, I dynamically create a set of labels and text boxes based on a public variable set in the form making the call.
I understand that the form is not closed or destroyed but simply hidden between calls, and as such I added code at the top of my Form_Shown event to clear out any controls from a previous call, but the controls aren't being removed. I have tried ctrl.Dispose (as in the code below) and Me.Controls.Remove(ctrl). Neither produces an error, but the Textboxes are not removed and new ones are created over them. (For some reason,
This is the first time I've dynamically created/removed controls in .NET, so it's possible my yearning for VB6's control arrays have something to do with the error.
The form builds itself based on the calling form's public ListView variable. The calling form makes certain this variable is not nothing and that items are selected if and only if the user is editing an existing row.
Public Class frmTableEdit
Private isNew As Boolean
Private inputText() As TextBox
Private Sub FormTableEdit_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
For Each ctrl As Control In Me.Controls
If TypeOf (ctrl) Is TextBox Or TypeOf (ctrl) Is Label Then
ctrl.Dispose()
End If
Next
With frmKioskData.TBLobj
Dim fieldCount As Integer = .Columns.Count - 1
isNew = .SelectedIndices.Count = 0
'(code setting size of form and location of OK/Cancel buttons is here)
ReDim inputText(fieldCount)
For i As Integer = 0 To fieldCount
Dim lbl As New Label, txt As New TextBox
inputText(i) = txt
Me.Controls.Add(lbl)
Me.Controls.Add(txt)
'(code setting size and and position of lbl & txt is here)
'lbl.Tag = i (I commented these lines out because I never used the
'txt.Tag = i Tag property, but can if a solution calls for it.)
lbl.Text = .Columns(i).Text
If isNew Then
txt.Text = ""
Else
txt.Text = .Items(.SelectedIndices(0)).SubItems(i).Text
End If
Next
End With
End Sub
End Class
If #Plutonix's suggestion in the comment above does not quite work for you, I think it would be easiest and make more sense to dispose of the form after calling ShowDialog, and then when you need to show that form you create a new instance with a parameter that tells it what dynamic controls to load.
So you'd have a New method in frmTableEdit that uses this parameter:
Public Sub New(ByVal fieldCount As Integer)
InitializeComponent()
fieldCount = fieldCount 'Where fieldCount is a class variable
End Sub
And when you call this form from frmKioskData, you can do so like this:
Dim newTableEdit As New frmTableEdit(Me.TBLobj.Columns.Count - 1)
newTableEdit.ShowDialog()
newTableEdit.Dispose()
Then the code in your frmEditTable's Shown event just simply has to add the controls accordingly, without the need to remove old ones:
ReDim inputText(fieldCount)
For i As Integer = 0 To fieldCount
Dim lbl As New Label, txt As New TextBox
inputText(i) = txt
Me.Controls.Add(lbl)
Me.Controls.Add(txt)
'(code setting size and and position of lbl & txt is here)
'lbl.Tag = i (I commented these lines out because I never used the
'txt.Tag = i Tag property, but can if a solution calls for it.)
lbl.Text = .Columns(i).Text
If isNew Then
txt.Text = ""
Else
txt.Text = .Items(.SelectedIndices(0)).SubItems(i).Text
End If
Next
How you get the isNew value is up to you - you can add that as a second parameter to the form's New, or get it the same way you are now...w/e. If it were me I'd normally add that as another New parameter.