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

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

Related

Dynamically generated buttons from XML always have the same attributes of the last node in XML file

Using the below function, a series of buttons are generated into a flow layout panel based on an existing XML document.
The function is called at program load, and successfully generates buttons with different attributes, until they are clicked.
When the buttons are clicked, they should output it's attributes to a data grid view panel, but it only enters the attributes of the last node in the XML document.
Function loadMenuItems() As Double
m_xmld = New XmlDocument
m_xmld.Load("Menu.xml")
m_nodelist = m_xmld.GetElementsByTagName("menuItems")
For Each m_node In m_nodelist
Dim newButton As New Button
strID = m_node.Item("ID").InnerText
strName = m_node.Item("Name").InnerText
strPrice = m_node.Item("Price").InnerText
strOptions = m_node.Item("Options").InnerText
newButton.Name = "BTN_" & strID
newButton.Width = 150
newButton.Height = 150
newButton.BackgroundImageLayout = ImageLayout.Zoom
newButton.TextImageRelation = TextImageRelation.TextAboveImage
newButton.ForeColor = Color.White
newButton.Text = strName
AddHandler newButton.Click, Sub()
DGV_Receipt.Rows.Add(strName, strOptions, strPrice)
End Sub
newButton.BackgroundImage = Image.FromFile(".\Resources\Icons\" & strName & ".png")
FLP_Icons.Controls.Add(newButton)
Next
End Function 'end the function definition.
The function being loaded:
Private Sub FORM_Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
loadMenuItems()
End Sub
I am a beginner at VB, so if I'm missing something obvious, please let me know!
As suggested in the comments, the issue is your event handler. There is some nuance in how Lambda expressions work and you are running afoul of that.
One option would be to store the correct data in the Tag property, which is a general-purpose data field, of each Button, e.g.
newButton.Tag = {strName, strOptions, strPrice}
and then get the data back from the Button in the event handler:
AddHandler newButton.Click, Sub(sender, e)
Dim btn = DirectCast(sender, Button)
Dim data = DirectCast(btn.Tag, String())
DGV_Receipt.Rows.Add(data(0), data(1), data(2))
End Sub
Alternatively, define your own custom class that inherits Button, add dedicated properties for those values and then use them in your code. That custom class will work just like a regular Button but you can set those properties when you create it and then get the data back from them in the event handler.

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 reference a variable control on a variable form from another form? Need to get the button.Tag renamed in running program

Here's my problem:
I have a form with a treeview.
That treeview shows all:
other forms in my project as parents
all buttonnames as childs
all buttontags as childs of the buttonnames.
When i select a buttonname in the treeview i have the selection presented as
(textbox1 with the buttonname)
(textbox2 with the buttontag)
(textbox3 with the formname)
I have 1 empty textbox which i want to fill manually, to update the buttontag from the button selected in the treeview.
Either way, all code I have tried ain't updating anything.
This is the code so far, but doesn't seem to work...
My Code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim asm = System.Reflection.Assembly.GetExecutingAssembly
Dim myTypes As Type() = asm.GetTypes()
Dim frm As Form
For Each t As Type In myTypes
If t.IsSubclassOf(GetType(System.Windows.Forms.Form)) AndAlso TextBox1.Text = t.Name Then
frm = CType(Activator.CreateInstance(t), Form)
frm.Hide()
Dim thisButtonName As String = TextBox3.Text ' This is the name of the button I'm looking for
Dim thisButtonName2 As String = TextBox2.Text ' this is the new tag name for that button
' Loop all controls in this form
For Each ctrl As Control In Controls
' Is this control a button
If TypeOf (ctrl) Is Button Then
' Is this the correct button
If CType(ctrl, Button).Name = thisButtonName Then
CType(ctrl, Button).Tag = thisButtonName2
End If
End If
Next
End If
Next
TreeView1.Nodes.Clear()
For Each formprop In My.Forms.GetType.GetProperties
Dim node = Me.TreeView1.Nodes.Add(formprop.Name)
Dim form As Form = CType(formprop.GetValue(My.Forms, Nothing), Form)
ControlsTree(node, form.Controls)
Next
End Sub
I think there are two basic problems here:
Your loop For Each ctrl As Control In Controls is not iterating over the controls in the other form object referenced by the frm variable. The Controls property is going to default to this form's set of Controls, not frm.Controls.
It seems like you are trying to change the Tag in the definition of that class at run-time. That is not possible, AFAIK, especially in what you're trying here. Each time you create a new instance of that form object, you are going to get that object initialized as how it was compiled. You can change the Tag values of a running instance of the object, but you can't change the default values of the class without using a technique like dependency injection.

How to get value from dynamically created texboxes?

im new here and im having some problem with my vb.net code. I have dynamically created few textboxes on panel, and I want my code after submitting the form to save those values into database. Problem is that I just cannot find the way how to grab values from those texboxes. I tried everything that i found on internet but i still getting the error message "Object reference not set to an instance of an object". Can someone advice me what am i doing wrong.
Here is the code how i created texboxes:
for i As Integer = 0 To cntPos -1
Dim txtJobTo as TextBox = new TextBox()
txtJobTo.ID = "txtJobTo_" & jobID
Dim label as Label = new Label()
label.text = posPanel.Rows(i).Item("Position")
pnlContainer.Controls.Add(label)
pnlContainer.Controls.Add(new LiteralControl("</td><td>"))
pnlContainer.Controls.Add(txtJobTo)
next
This line of code is shows those texboxes on page
<tr bgcolor="#FFCC99"><td colspan="4">
<asp:Panel ID="pnlContainer" runat="server" Visible="true"></asp:Panel></td></tr>
<tr><td colspan='6' align='center'> <asp:Button ID="cmdSave" Text="Save" ToolTip="cmdSave" CommandArgument="cmdSave_Click" runat="server" /></td></tr>
And this is part of the code that should save all data
Sub cmdSave_Click(ByVal sender As System.Object, e As EventArgs) Handles cmdSave.Click
...
for i As Integer = 0 To cntPosIns -1
Dim strTo as TextBox = New TextBox()
posID = posIns.Rows(i).Item("ID_Pos")
strTo.Text =CType(pnlContainer.FindControl("txtJobTo_" & posID.ToString()),TextBox).Text
....
'Insert into database
next
I always get error message on this line strTo.Text =CType(pnlContainer.FindControl("txtJobTo_" & posID.ToString()),TextBox).Text
Can someone please give me some advice on how to fix this? What is the proper way to read value from dynamically created textboxes in this situation?
Thank you
there are two aspects to this I think. Dynamic controls are a bit of a minefield and can take a while to understand.
a) Make sue to create the dynamic controls and add them to the page during OnInit or CreateChildControls. Access the value in the event handler or during OnPreRender...otherwise you will have trouble using the standard TextBox.Text property to get the value. It's tricky using dynamic controls because the values are not present for the whole page lifecycle without inspecting the page.request property.
b) Personally, when I dynamically create input elements, I don't "let go" of them and rely on findControl to get a handle back onto them for me.
When I create controls dynamically, I store them in a look up e.g. a lovely Dictionary(of string, TextBox) which is accessible to the rest of the code, e.g. a property or member variable.
' Lookup declared outside of the consuming methods so it is accessible to both
private dictControlsLookup as new dictionary(of string, textbox)
Sub YourSubName
for i As Integer = 0 To cntPos -1
Dim txtJobTo as TextBox = new TextBox()
txtJobTo.ID = "txtJobTo_" & jobID
Dim label as Label = new Label()
label.text = posPanel.Rows(i).Item("Position")
pnlContainer.Controls.Add(label)
pnlContainer.Controls.Add(new LiteralControl("</td><td>"))
pnlContainer.Controls.Add(txtJobTo)
dictControlsLookup.Add(txtJobTo.ID, textJobTo)
next
End Sub
Sub cmdSave_Click(ByVal sender As System.Object, e As EventArgs) Handles cmdSave.Click
...
for i As Integer = 0 To cntPosIns -1
Dim strTo as TextBox = New TextBox()
posID = posIns.Rows(i).Item("ID_Pos")
dim ctlId as string = "txtJobTo_" & posID.ToString()
If dictControlsLookup.ContainsKey(ctlId) Then
strTo.Text = dictControlsLookup(ctlId).Text
End If
....
'Insert into database
next
End Sub
Alternatively you could just iterate the dictControlsLookup.Values collection in save_click to access all the text boxes :-)

How to change only one tooltip?

I am populating a FlowLayout with Pictureboxes. As I populate i give each of them a tooltip. I have a seperate function to change the pictures how can I change the tooltip as well?
dim laytt as tooltip = new tooltip
For i = 1 To count
Dim newPic As PictureBox = New PictureBox()
newPic.Image = p.Image
newPic.Size = p.Size
newPic.SizeMode = p.SizeMode
laytt.SetToolTip(newPic, ttstring)
AddHandler newPic.Click, AddressOf LayoutComponent_Clicked
sys.Add(a_component)
LayoutFlowLayout.Controls.Add(newPic)
Next
later i have a function to change the pics in it I want to be able to change the tool tip
Private Sub LayoutComponent_Clicked(ByVal sender As Object, ByVal e As EventArgs)
Dim i As Integer = LayoutFlowLayout.Controls.IndexOf(sender)
If deleteModeOn Then
sys.components.RemoveAt(i)
LayoutFlowLayout.Controls.RemoveAt(i)
Exit Sub
End If
'get index in sys from layout?
If (sys.components.Item(i).GetType() = GetType(Transpositor)) Then
Form2.ShowDialog(Me)
sys.components.Item(i).divert = tempTranspositorDivert
'here I want to do something like this
laytt.RemoveAt(i) <--- THIS DOESN'T EXIST
End If
End Sub
TL;DR I want to remove/change only one tooltip text at a specific index
Since the sender parameter is the picture box control that was clicked, you can use that variable to specify which control you want to alter. For instance, this will remove the tool tip:
laytt.SetToolTip(sender, Nothing)
This will change it:
laytt.SetToolTip(sender, "new value")