VB.Net Dynamically Referencing a Variable or Control - vb.net

It would take too long to try an explain the actual application I am building.
Lets just say, I have 3 textboxes on my form. I want to set each one of them to a value of the numerical index. This is how I would normally do it.
txt1.Text = "1"
txt2.Text = "2"
txt3.Text = "3"
Now, if I had 100 of these textboxes, I would want to do something more like this.
For i as Integer = 1 to 3
txt[i].Text = i
Next
Is this possible?

This is how I would do it: first, create a list or an array (depending on whether the number of textboxes is fixed or not) and add you textboxes to it:
Dim txtList as new list(of textbox)
txtList.items.add(txtBox1...
This can be done automatically using jmcilhinney's method (with the same caveats):
Dim txtList = New List(Of TextBox)(Me.Controls.OfType(Of TextBox)().ToArray())
Then you can reference it as such:
txtList(i).text
I hope that's what you were asking and that it helps :)

Related

How to check datagridview column already exists with same Header Text Before adding a new Column in VB.net

I am trying to add columns dynamically to data grid view using VB.net. But the issue is I need to check that the column name already exists. before adding it if exists I want it to be cancelled automatically. I am using another form to select the Job Nos. which will add as Datagridview Header Text when it saved. () below is the code I am using to add a column to my datagridview. Hope you understand the question. I found some nearby answers in C# unfortunately I am not able to convert those correctly as my C# coding knowledge is little weak.
Thank You!
Dim FRMP = FrmEReview.ReviewGrid.Columns
Dim NOHRS As New DataGridViewTextBoxColumn
FRMP.Add(NOHRS)
NOHRS.HeaderText = Me.Cmb_CName.Text & "-" & Me.Cmb_DName.Text
NOHRS.Width = 160
The obvious option - the one you should have been able to work out for yourself - is to simply loop through the columns and test the HeaderText of each one:
Dim headerText = $"{Cmb_CName.Text}-{Cmb_DName.Text}"
Dim headerTextFound = False
For Each column As DataGridViewColumn In FrmEReview.ReviewGrid.Columns
If column.HeaderText = headerText Then
headerTextFould = True
Exit For
End If
Next
If Not headerTextFound Then
'...
End If
This is basically the code equivalent of what you'd do manually, which is why you should have been able to do it for yourself, at least mostly.
The not-so-obvious solution for a beginner is to use LINQ. LINQ is basically a means to flatten loops like this, so it leads to far more succinct code:
Dim headerText = $"{Cmb_CName.Text}-{Cmb_DName.Text}"
If FrmEReview.ReviewGrid.
Columns.
Cast(Of DataGridViewColumn)().
All(Function(dgvc) dgvc.HeaderText <> headerText) Then
'...
End If

Update NumericUpDown.Maximum from corresponding txt.text control using for each loop

As newbie in VBA.net i want to solve following.
I have a form with 38 text controls in 4 groupboxes. These get filled by clicking a row in a datagridview. I have 38 corresponding NUD's where i want the maximum to be equal to its corresponding text.
A 'pair' is always in one of the 4 groupboxes. Besides that there are also textboxes on the form itself to control the DGV.
I have a naming convention that makes it possible to match them easily . NUDGeel corresponds with txtGeel , NUDRood with TxtRood, NUDGroen with txtGroen etc et
Now that update is easily done if you do them one by one
NUDGeel.maximum = txtGeel.text
NUDRood.maximum = txtRood.text
etc
What i want to achieve is that this gets done in a for each loop. (Order to prevent me typing this 38 times (and also just to 'understand' it)
I can figure out how to start the loop
Dim c As Control
For Each c In Me.Controls
If TypeName(c) = "NumericUpDown" Then
'do some magic
End If
Next
I have tried to search for the magic code, and i guess from research it is pretty simple, i just donot get it .
Anyone with an idea how to fix ?
For Each tb In Controls.OfType(Of TextBox)
Dim nud = DirectCast(Controls(tb.Name.Replace("txt", "NUD")), NumericUpDown)
If nud IsNot Nothing Then
nud.Maximum = CDec(tb.Text)
End If
Next
You don't need the If statement if there are no other TextBoxes on the form besides those with corresponding NumericUpDowns.
Private Sub SetMaximum()
Dim controlNames() As String = {
"Geel", "Rood", "Name1", "Name2", ' list all the names of your controls here excluding NUD/txt
}
For Each controlName As String In controlNames
CType(Me.Controls("NUD" & controlName),NumericUpDown).Maximum = CType(Me.Controls("txt" & controlName),TextBox).Text
Next
End Sub
This assumes that all the controls are not inside any containers. If they are, you must use the container (panel, groupbox, etc) instead of Me.

VB declaration of table

I have a little problem: I want to make some app in VB and I make two CheckedListBoxs and I have some idea: if I chose something in CheckedListBox1 I want to show some date inside CheckedListBox2.
I have a problem with declaration - I make something like this:
Dim model3 = {"A", "B", "C"}
But I have only one information inside CheckedListBox2: 'String[]'
If CheckedListBox1.CheckedItems.Count <> 0 Then
If CheckedListBox1.SelectedItem.ToString = "GWW" Then
Marka.Items.Add(model1)
ElseIf CheckedListBox1.SelectedItem.ToString = "AWW" Then
Marka.Items.Add(model2)
ElseIf CheckedListBox1.SelectedItem.ToString = "ZWW" Then
Marka.Items.Add(model3)
End If
Else
Marka.Items.Clear()
End If
Could you give me some prompt? I do not have too much experience so if I could asked as simple as possible :)
That's because you're only adding one item - the array itself - and the CheckedListBox will call its ToString method to get text that it can display, which is what you see. If what you actually want to do is add all the elements in the array into the CheckedListBox then you need to call AddRange rather than Add.

How can I use value of a string to control another control in VB.net?

I have been playing around with some code, and I have made easily 50+ controls that all are labeled: PictureBox[XCoordinate]_[YCorrdinate] (Replacing the brackets and contents with the coordinates of them on a little grid I made.)
The problem with this is it is a real pain to use a control when doing loops to update all the picture boxes. I want to know how to do code like:
'This code assumes that the picture boxes are all initialized.
Dim XCoordiante As Integer = 5
Dim YCorrdinate As Integer = 2
PictureBox[XCoordinate]_[YCoordiante].Image = [Put Image Here]
I am going to put this within a loop. Is there a way that I can do this without manually typing it all and risking missing something within a case statement? And also, I would have to retype it for every different kind of change I want to make (ex: tag or error image).
Would a pointer somehow help? I don't really know how to do this, but it would be really helpful if possible.
When you create them, save them to a List:
Private pList As New List(Of PictureBox)
Dim pic As New PictureBox
With Pic
.Location = ...
' etc
End With
Me.Controls.Add(pic)
pList.Add(pic)
Assuming they are created in some sort of order:
For n As integer = 0 To pList.Count = 1
' add code to look at Plist(n).X and .Y to determine what to do (?)
Plist(n).Image = ...
Next n
If there is more info to capture, create a custom class of a PicBox and the other info, and make the list a List(Of myPicClass).

How should I handle filling multiple textboxes when I don't know how many of them will have data?

I'm writing an application in VB in which I need to show the user some information which will be copy and pasted into another application however limitations of the other application mean that the string needs to be split into chunks no larger than 55 characters (it's just written notes). I thought the neatest way to do this was to have several textboxes each with a 'copy to clipboard' button to make it convenient for the user.
The code I have is:
Dim invdesc As List(Of String) = Split(splitstring, 55)
txtinvDesc1.Text = invdesc(0)
txtinvDesc2.Text = invdesc(1)
txtinvDesc3.Text = invdesc(2)
...
Split uses a regular expression to return a list of several lines without breaking up words and most of the time this will return a maximum of seven results but occasionally six (my original string max length is 330) and often fewer so my original idea to fill out any strings shorter than 330 with trailing spaces won't work as it's still possible I will either miss text or call a result that isn't there.
Ideally I would just do some kind of loop that only inputs to txtinvDesc(x) while there is data available and ignores the rest (or hides them) but I don't know any way to refer to a textbox other than explicitly or how to put them in any kind of list/array.
So it's a bit of an open question in "how best can I handle this requirement?"
You can create a collection (e.g., Array or List) of TextBox like with any other type/class (as you are doing with String in your code). Sample:
Dim allTextBoxes As New List(Of TextBox)
allTextBoxes.Add(txtinvDesc1)
allTextBoxes.Add(txtinvDesc2)
allTextBoxes.Add(txtinvDesc3)
Alternatively, you might iterate through all the controls in the main form by checking its type (a textbox or not). In that case you would have to set a relationship between the given name of the textbox and the data list index, via other collection for example:
Dim mappingList As New List(Of String)
mappingList.Add("txtinvDesc1")
mappingList.Add("txtinvDesc2")
mappingList.Add("txtinvDesc3")
For Each ctr As Control In Me.Controls
If (TypeOf ctr Is TextBox AndAlso mappingList.Contains(ctr.Name)) Then
ctr.Text = invdesc(mappingList.IndexOf(ctr.Name))
End If
Next
--- CLARIFICATION (not as evident as I thought)
The proposed for each loop relies on a mapping approach, that is, it relates each element in invdesc with the corresponding TextBox name. By definition, both arrays HAVE TO have the same number of elements (otherwise the mapping system wouldn't have made any sense). This is the most efficient and overall-applicable alternative; if the names of the textboxes and invdesc have elements in common (e.g., the numbers), you might just compare the names. BUT WHEN MAPPING YOU HAVE TO ACCOUNT FOR ALL THE ELEMENTS (if there is no associated TextBox to a given item, let the value blank; but all the items have to be accounted).
If you want to index the tbs:
Private TBs as New List (of TextBox)
Early on (after FormLoad) maybe in a FormSetup:
TBs.Add(txtinvDesc1)
TBs.Add(txtinvDesc2)
TBs.Add(txtinvDesc3)
...
Then:
Dim invdesc As List(Of String) = Split(splitstring, 55)
For n As Integer = 0 To invdesc.Count-1
TBs(n).Text = invdesc(n)
Next
' handle the varying 7th TB:
For n As Integer = invdesc.Count-1 To TBs.Count - 1
TBs(n).Enabled = False
TBs(n).Text =""
Next
Or a For/Each:
Dim ndx As Integer = 0
For Each tb As TextBox In TBs
tb.Text = invdesc(ndx)
ndx += 1 ' thanks varo!
Next
Then hide/disable or at least clear the text from any empty ones.
If it turns out there are always 6 you really only need an if statement:
txtinvDesc1.Text = invdesc(0)
txtinvDesc2.Text = invdesc(1)
txtinvDesc3.Text = invdesc(2)
...
If incDesc.Count-1 = 6 Then
txtinvDesc7.Text = invdesc(6)
Else
txtinvDesc7.Enabled= False
txtinvDesc7.Text = ""
End If
I would change the TB names to start at txtinvDesc0.Text to avoid getting confused (as I may have)
Use multiline textbox and in OnKeyPress event force 55 chars per line. You can find subclassed TextBox with that feature in this SO answer :
https://stackoverflow.com/a/17082189/351383