Sorting List of Control by name - vb.net

I'm trying to sort list of Controls by their name. This is my code to loop through Form Controls and add them to list.
Public Sub FindControls(ByVal owner As Control, ByVal list As List(Of Control), ByVal name As String)
'list.Clear()
For Each c As Control In owner.Controls
If c.Name.Contains(name) And c.Name.Length < 4 Then
list.Add(c)
End If
If c.HasChildren Then FindControls(c, list, name)
Next
End Sub
Then i want to loop through this list and get value from these controls by index.
For i As Integer = 0 To ElektrikList.Count - 1
If ElektrikList(i).Name = "T" & i.ToString Then
'do something
End If
Next
I named all my controls "T00" (example: "T1" or "T50"), but they are added to the list with wrong order, so for example index 4 in this List is T23, not T4 as I would wish.
Is there any way to sort it? I tried everything i found but I can't get it to work.
At first i tried to create all these controls dynamically, but I want to add them on different Panels with categories and so on, so i thought it would be really painful to make this.

Would something like this work?
Dim sorted = From ctrl In owner.Controls
Order By ctrl.Name
For Each c As Control In sorted
(...)
I followed the example from Introduction to LINQ in Visual Basic.

I named all my controls "T00" (example: "T1" or "T50"), but they are
added to the list with wrong order
If you're only interested in those specific controls, then search for them in that order using the recurse option of Controls.Find() and add them to your list:
Public Function FindControls() As List(Of Control)
Dim ctrls As New List(Of Control)
For i As Integer = 1 To 50
Dim ctrlName As String = "T" & i.ToString("00")
Dim ctrl As Control = Me.Controls.Find(ctrlName, True).FirstOrDefault
If Not IsNothing(ctrl) Then
ctrls.Add(ctrl)
End If
Next
Return ctrls
End Function

Related

Visual Basic Iterative enabling of Textbox's

Si I'm working on an assignment where I have 10 RadioButtons indicating how many contesters I have, and depending on what I pick between 1 to 10, I need that many of my corresponding TextBoxes to be enabled so I could fill it with names!
Is there a way for me to make a For loop between 1 and the number I picked from the RadioButton and say something like
For i = 0 to Size
{
TextBox&i.Enabled = True
}
Since my TextBoxs are called TextBox1 to TextBox10
I know you can add strings together using &, but how can I do that for an object name?
As of right now I literally have the dumbest way of doing it, which is a click event inside each RadioButton that manually enables the correct number of TextBoxes...
Thank you in advance!
You can iterate over all controls like this:
For Each ctr In Me.Controls
Dim indx As String = ctr.Name
If TypeOf (ctr) Is Textbox Then
' Now compare the name with TextBox&i and do smth
End If
Next
It's not possible to just concatenate a string and use it as an object variable reference like that, but you can search the form's controls by their name property (which is a string) and do it that way. Here's an example:
Private Sub EnableTextBoxes(ByVal Size As Integer)
For i As Integer = 1 To Size
Dim matches() As Control = Me.Controls.Find("Textbox" & i.ToString, True)
If matches IsNot Nothing AndAlso matches.Length = 1 Then matches(0).Enabled = True
Next
End Sub

Adding stuff to listview from textbox

id like to know how to take one of my text boxs or strings and put it in a listview.. well not really let me show u wants going on.
i have a 2 text box with the following stuff
TextBox1
cat123
hatcat
quanwall
samiam12
TextBox2
John
will
sam
dan
i want to take TextBox1's text and put it in one of the columns in the ListView. for example. ListView has 2 columns saying usernames and realnames, and TextBox1 is the usernames and TextBox2 is the realnames. So i want to take each line in TextBox1 to match up with the RealNames(TextBox2) all in ListView.
iv bin using the
Dim Q As New ListViewItem
Q.Text = Host
Q.SubItems.Add(User)
Q.SubItems.Add(Pass)
ListView1.Items.Add(Q)
to add the strings to the listview
I need this information ASAP, Thx u <3
Try this (To listview1 put your listview name)
Dim i As Integer = 0
For Each l In TextBox1.Lines
ListView1.Items.Add(l)
ListView1.Items(ListView1.Items.Count - 1).SubItems.Add(TextBox2.Lines(i))
i += 1
Next
i = 0
While the straightforward answer to your question is rather simple, your posted question raises issues. You are using Listbox and Listview interchangeably, yet they are two different controls. Moreover you seem to suggest your Textbox holds multiple values where the intention of a Textbox is to hold one distinct value or string of text.
As these controls are Windows Forms controls, your use of "Dim Q As New ListviewItem" may not be neccessary.
I would suggest reading up more on the controls you want to use, how they are used and in what context.
The simple straightforward answer to your question could be:
listBox1.Items.Add(textBox1.Text)
For reference: How to: Add and Remove Items with the Windows Forms ListView Control
I'm assuming your user names are stored in TextBox1 and your real names are stored in TextBox2
Public Sub AddListViewItemsFromTextboxes()
Dim Host As String = "SomeHost" 'you mentioned a host in the code snippet in your question, not sure where this comes from
Dim TextBox1String As String = TextBox1.Text
Dim TextBox2String As String = TextBox2.Text
Dim TextBox1Lines() As String = TextBox1String.Split(vbNewLine)
Dim TextBox2Lines() As String = TextBox2String.Split(vbNewLine)
If(TextBox1Lines.Count <> TextBox2Lines.Count)
'possible error handling here
MsgBox("Each user must have both a real name and a username.")
Exit Sub
End If
For NameIndex As Integer = 0 to (TextBox1Lines.Count - 1)
Dim UserName As String = TextBox1Lines(NameIndex)
Dim RealName As String = TextBox2Lines(NameIndex)
Dim Item As New ListViewItem
Item.Text = Host
Dim UserNameSubItem As New ListViewitem.ListViewSubItem
UserNameSubItem.Text = UserName
Item.SubItems.Add(UserNameSubItem)
Dim RealNameSubItem As New ListViewItem.ListViewSubItem
RealNameSubItem.Text = RealName
Item.SubItems.Add(RealNameSubItem)
ListView1.Items.Add(Item)
Next
End Sub
Example GUI:
http://i.stack.imgur.com/du95F.png
EDIT: Added third column

VB.NET Iterating Form Labels

I have several label boxes on my design form that all share the naming convention lbl_#.text where # ranges from 1 to 60. I want to make a loop that iterates through each lbl_#.text adding some incremental value, let's say multiples of 2 for this question's theoretical purpose.
Something such that the end result would amount to the following:
lbl_1.text = "2"
lbl_2.text = "4"
lbl_3.text = "6"
...
lbl_60.text = "120"
I'm not sure how to access each of these labels through the coding side, I only know how to explicitly mention each label and assign a value :/
There are a few options here.
In this situation the labels will often have a common container, such as panel or groupbox control. In that case:
Dim formLabels = myContainerControl.Controls.OfType(Of Label)()
For Each formLabel As Label In formLabels
'...
Next formLabel
Of course, this mixes logical groups with visual groupings. Those two things don't always align well, so you can also...
Add them all to a Label array (or List(Of Label) or any other enumerable):
Dim formLabels(60) As Label = {lbl_1, lbl_2, lbl_3 .... }
For Each formLabel As Label in formLabels
'...
Next formLabel
But sometimes that's more trouble than it's worth, even if you use a loop to create the collection, and so you can also
Use the .Name property (in conjunction with a naming convention to identify your desired controls):
Dim formLabels = Controls.Where(Function(c) c.Name.StartsWith("lbl_"))
For Each formLabel As Label In formLabels
'...
Next formLabel
Some combination of the above (for example, code in the form load event to create a list based on the name property).
Notice the actual For Each loop is exactly the same in all of those options. No matter what you do, get to the point where you can write a single expression to identify the label control, and then run a simple loop over the expression result.
This points to a final strategy: think in terms of binding to a data source. With a data source, your labels are created as part of a DataGridView, FlowLayoutPanel, or similar control. Then you can iterate the rows in the grid or panel.
Use the Controls collection:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim i As Integer
For i = 1 To 3
Dim myLabel As Label = CType(Me.Controls("lbl_" & i), Label)
myLabel.Text = ...whatever value you want to put here
Next
End Sub
End Class
If you don't know how many labels there are, one option is to use a Do Loop.
Dim lblTarget As Label = Nothing
Dim intCursor As Integer = 1
Dim bolFirstIteration As Boolean = True
Do Until lblTarget Is Nothing AndAlso Not bolFirstIteration
If bolFirstIteration Then
bolFirstIteration = False
End If
lblTarget = CType(Me.Controls("lbl_" & intCursor.ToString()), Label)
If Not lblTarget Is Nothing Then
lblTarget.Text = (intCursor * 2).ToString()
End If
intCursor += 1
Loop

VB.NET Combobox - Auto-complete behaviour for numeric values

I have a problem with the auto-complete behaviour of comboboxes in VB.NET (with the .NET framework 2.0).
I am using a combobox to type in numeric values, and its DropDown list to suggest possible numeric values. This list is sorted in ascending order, for example {"10","92", "9000", "9001"}.
The combobox properties are set as follow:
AutoCompleteMode: SuggestAppend
AutoCompleteSource: ListItems
DropDownStyle: DropDown
Sorted: False
The DropDown list is simply filled like this:
myCombobox.Items.Add("10")
myCombobox.Items.Add("92")
myCombobox.Items.Add("9000")
myCombobox.Items.Add("9001")
When I don't type anything, the order of values of the DropDown list is correct, in original/ascending order. However, when I start typing something, the suggested values in the DropDown list get sorted (alphanumerically): if I type "9", the list of suggestions becomes {"9000", "9001", "92"}.
I would like to prevent this behaviour to get the values of the list in the original/ascending order. I can't figure out how...
A possible work-around would be to pad with zeroes the values in the list, e.g. {"0010", "0092", "9000", "9001"} but I would like to avoid this.
Edit:
As suggested by bendataclear, one can use a list box to display the suggestions.
This will work for small lists but doesn't scale well to large lists. It may be useful for some applications. Based on the code given by bendataclear, I made it work this way:
Private Sub ComboBox1_KeyUp(sender As System.Object, e As System.Windows.Forms.KeyEventArgs) Handles ComboBox1.KeyUp
Dim cursorPos As Integer = ComboBox1.SelectionStart
ListBox1.Items.Clear()
For Each s In ComboBox1.Items
If s.StartsWith(ComboBox1.Text) Then
ListBox1.Items.Add(s)
End If
Next
If ListBox1.Items.Count > 0 And ComboBox1.Text.Length > 0 Then
ComboBox1.Text = ListBox1.Items(0)
ComboBox1.SelectionStart = cursorPos
ComboBox1.SelectionLength = 0
End If
End Sub
The code has not been thoroughly tested and can be improved, but the main idea is there.
Edit 2:
Using DataGridView leads to better performance; it was sufficient for me. Thanks bendataclear.
Just out of curiosity, any other answer is welcomed :)
Seems to be an issue when the combo box displays the data, as even if you set a custom source it re-orders alphabetically:
ComboBox1.Items.Add("10")
ComboBox1.Items.Add("92")
ComboBox1.Items.Add("9000")
ComboBox1.Items.Add("9001")
ComboBox1.AutoCompleteCustomSource.Add("10")
ComboBox1.AutoCompleteCustomSource.Add("92")
ComboBox1.AutoCompleteCustomSource.Add("9000")
ComboBox1.AutoCompleteCustomSource.Add("9001")
ComboBox1.AutoCompleteSource = AutoCompleteSource.CustomSource
I think the only way I can think of is to create your own autocomplete something like (untested):
Dim cbotxt As String = ComboBox1.Text
Dim key As String
key = ChrW(e.KeyCode)
ListBox1.Items.Clear()
For Each i In ComboBox1.Items
Dim s As String = i.ToString()
If s.StartsWith(ComboBox1.Text & key) Then
ListBox1.Items.Add(s)
End If
Next
If ListBox1.Items.Count > 0 Then
ListBox1.Visible = True
ComboBox1.Text = ListBox1.Items(0)
End If
Edit:
A good approach for many items (I'm using for 10000+ in an application):
First change from a list box to a datagridview.
Then declare a list of strings and fill with values you want to autocomplete
Dim Numberlist as List<Of String>
' Fill List using Numberlist.Add("String")
Then in the text change property:
Filter = NumberList.FindAll(AddressOf checkNum)
DataGridView1.DataSource = Filter
And add the function to check the strings.
Function checkNum(ByVal b As String) As Boolean
If b.StartsWith(ComboBox1.Text) Then
Return True
Else
Return False
End If
End Function
This method runs on my machine with 10k items faster than I can type.

im having syntax issues pulling data from 6 text boxes with identical names (other than a number at the end) in a for loop

I have 6 different text boxes with similar names:
txtBox1, txtBox2....txtBox6
I also have an array:
dim intValue (0 to 5) as Integer
Now I want to use a for loop to assign the value in each text box to a corresponding space in the array, concatenating the value of the loop counter with the string "txtBox" and retrieving the data using the .text method.
here is my code:
For count As Integer = 0 To 5
Dim strCount As String = count
Dim strTxtBox As String = "txtBox" & strCount
intValues(count) = Convert.toInt32(strTxtBox.Text)
Next
the issue is that the string name doesn't point to txtBox1, txtBox 2 etc.
Thanks in advance for the help.
If you want to access the control name, you have to use the property "Name".
You should try something like that:
For i As Integer = 0 To 5
For Each c As Control In Controls
If c.Name = "txtBox" & i Then
intValue(i) = Convert.ToInt32(c.Text)
End If
Next
Next i
The above code is just an example, but it should work for you.
Anyway you can write a better code checking the type of the control or maybe using a different loop logic, but the basic idea is that if you want to use in your code the name od the control you have to use the NAME property.
strTxtBox is a string, nothing more. You cannot refer to control names by String without special code. Rather than go down that path, I'd create an array and populate it with text boxes:
Dim txtBoxes As TextBox() = {txtBox1, txtBox2, txtBox3, txtBox4, txtBox5, txtBox6}
Dim intValues As Integer(0 To 5)
For count As Integer = 0 To 5
intValues(count) = Convert.ToInt32(txtBoxes(count).Text)
Next
The easiest way is to iterate through the contents of Controls to find the textboxes. You can either:
Use the .Tag property to label textboxes to identify them, or as the other answer points out, use the .Name property.
If you have a lot of other controls on the form, and they may not be in order, you could also check each control to see if it's a textbox. Assume they are in reverse order, as the Controls array goes from end to beginning.
Dim nums() As Integer = {10, 20, 30, 40, 50, 60}
Dim ctrl As Control
For Each ctrl In Me.Controls
If TypeOf (ctrl) Is TextBox Then
ctrl.Text = nums(Val(ctrl.Name(ctrl.Name.Length - 1)) - 1)
End If
Next
You could also instantiate an array of textboxes programmatically, but you'd have to set all of the placement, etc. by hand.
As I commented on the answer below, you may need to cast the ctrl to a System.Web.UI.Control to access the .Name, using DirectCast.