Accessing buttons names using variables - vb.net

In visual basic I want to be able to access a button's name using the number stored in a variable.
For example if I have 24 buttons that are all named 'Button' with the numbers 1, 2, 3... 22, 23, 24 after it. If I want to then change the text in the first eight buttons how would I do that.
Here's my example to help show what I mean:
For i = 1 to 8
Button(i).text = "Hello"
Next

The proposed solutions so far will fail if the Buttons are not directly contained by the Form itself. What if they are in a different container? You could simple change "Me" to "Panel1", for instance, but that doesn't help if the Buttons are spread across multiple containers.
To make it work, regardless of the Buttons locations, use the Controls.Find() method with the "searchAllChildren" option:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ctlName As String
Dim matches() As Control
For i As Integer = 1 To 8
ctlName = "Button" & i
matches = Me.Controls.Find(ctlName, True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is Button Then
Dim btn As Button = DirectCast(matches(0), Button)
btn.Text = "Hello #" & i
End If
Next
End Sub

For index As Integer = 1 To 8
CType(Me.Controls("Button" & index.ToString().Trim()),Button).Text = "Hello"
Next

Use LINQ and you're good to go:
Dim yourButtonArray = yourForm.Controls.OfType(of Button).ToArray
' takes all controls whose Type is Button
For each button in yourButtonArray.Take(8)
button.Text = "Hello"
Next
Or
Dim yourButtonArray = yourForm.Controls.Cast(of Control).Where(
Function(b) b.Name.StartsWith("Button")
).ToArray
' takes all controls whose name starts with "Button" regardless of its type
For each button in yourButtonArray.Take(8)
button.Text = "Hello"
Next
In any case, .Take(8) will iterate on the first 8 items stored inside yourButtonArray

Related

Remove specific row of TableLayoutPanel using dynamically created button of each row

So I am making a function that will populate the TableLayoutPanel from FileDialog Result then make a delete button for each row using a loop. Here's the code
Private PathtoFile1 As New List(Of String) 'this will contain all the selected file in the dialogwindow
Private rowLineDrawing As Integer = 0
Private selectedfilecountLineDrawing As Integer
Public Function AttachFileLineDrawing(TLP As TableLayoutPanel)
Dim dr = OpenFileDialog1.ShowDialog
If (dr = System.Windows.Forms.DialogResult.OK) Then
selectedfilecountLineDrawing = OpenFileDialog1.FileNames.Count
For Each FileName In OpenFileDialog1.FileNames
Try
Console.WriteLine(FileName.ToString)
PathtoFile1.Add(FileName.ToString)
Catch SecEx As Security.SecurityException
MessageBox.Show("Security error. Please contact your administrator for details.\n\n" &
"Error message: " & SecEx.Message & "\n\n" &
"Details (send to Support):\n\n" & SecEx.StackTrace)
Catch ex As Exception
'Could Not Load the image - probably permissions-related.
MessageBox.Show(("Cannot display the image: " & FileName.Substring(FileName.LastIndexOf("\"c)) &
". You may not have permission to read the file, or " + "it may be corrupt." _
& ControlChars.Lf & ControlChars.Lf & "Reported error: " & ex.Message))
End Try
Next
'MAKE SOMETHING HERE TO DISPLAY THE SELECTED ITEMS IN THE TABLELAYOUTPANEL OF THE SUBMIT PROGRESS
TLP.Controls.Clear()
TLP.RowCount = 0
rowLineDrawing = 0
For Each Path In PathtoFile1
Dim filepath As New Label
filepath.Text = Path
filepath.Width = Val(360)
'this button is for previewing the file
Dim btnPreview As New Button
AddHandler btnPreview.Click,
Sub(s As Object, e As EventArgs)
Dim btn = CType(s, Button)
MsgBox("This is Preview")
End Sub
'This button is for removing rows in the tablelayoutpanel
Dim btnRmv As New Button
Dim StringToIndex As String = Path 'THIS CATCHES EVERY PATH IN THE LOOP AND STORE IT TO THE VARIABLE WHICH THEN BE USED AS A COMPARABLE PARAMETER FOR THE INDEX SEARCH
Dim index = PathtoFile1.IndexOf(Path)
AddHandler btnRmv.Click,
Sub(s As Object, e As EventArgs)
Dim btn = CType(s, Button)
MsgBox(index)
PathtoFile1.RemoveAt(index) 'THIS LINE OF CODE REMOVE THE SPECIFIC ITEM IN THE LIST USING THE BTNRMV CLICK
'MAKE SOMETHING HERE TO REMOVE THE ROW IN THE TABLELAYOUTAPANEL
End Sub
TLP.SuspendLayout()
TLP.RowStyles.Add(New RowStyle(SizeType.Absolute, 20))
TLP.Controls.Add(filepath, 0, rowLineDrawing)
TLP.Controls.Add(btnPreview, 1, rowLineDrawing)
TLP.Controls.Add(btnRmv, 2, rowLineDrawing)
TLP.ResumeLayout()
rowLineDrawing -= -1
Next
End If
End Function
So I am trying to remove the row in the TableLayoutPanel together with the dynamic control. My approach is removing the selected item in the list and I achieved it properly but can't remove the row in the TableLayoutPanel. Any help is much appreciated!
EDIT
I have tried to use the provided module above but got this error
And got this error
Here is an extension method that will enable you to remove any row from a TableLayoutPanel by index:
Imports System.Runtime.CompilerServices
Public Module TableLayoutPanelExtensions
<Extension>
Public Sub RemoveRowAt(source As TableLayoutPanel, index As Integer)
If index >= source.RowCount Then
Throw New ArgumentOutOfRangeException(NameOf(index),
index,
"The row index must be less than the number of rows in the TableLayoutPanel control.")
End If
'Remove the controls in the specified row.
For columnIndex = 0 To source.ColumnCount - 1
Dim child = source.GetControlFromPosition(columnIndex, index)
If child IsNot Nothing Then
child.Dispose()
End If
Next
'Move controls below the specified row up.
For rowIndex = index + 1 To source.RowCount - 1
For columnIndex = 0 To source.ColumnCount - 1
Dim child = source.GetControlFromPosition(columnIndex, rowIndex)
If child IsNot Nothing Then
source.SetCellPosition(child, New TableLayoutPanelCellPosition(columnIndex, rowIndex - 1))
End If
Next
Next
'Remove the last row.
source.RowCount -= 1
End Sub
End Module
I tested that on 3 column by 4 row TableLayoutPanel containing a Label in each cell executing the following code twice:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TableLayoutPanel1.RemoveRowAt(1)
End Sub
The result was as expected, i.e. removing the second-from-top row each time. You may need to fiddle a bit more depending on what you want to happen row heights. I had the row heights set to equal percentages so the remaining rows grew proportionally to fill the space. If you want something different, you can add code accordingly. Note that you could create an almost identical method for removing columns.

JOIN the Strings of different textboxes and again SPLIT

I am new in vb.net, so not much familiar with all VB functions. While working on 1 Windows Application, while taking order we need to save product and its specification like weight, height, width, color, length, material etc.
since every product can have different specification so its is not possible to determine and provide for fields in database.
So, I decided to provide textboxes so user can enter name & value while entering product details. 1 textbox for name & other textbox for value.
like this
Textbox1 = "WEIGHT" TextBox2 = "10" '(Value of Weight)
Textbox3 = "WIDTH" TextBox4 = "5" '(value of Width)
Textbox4 = "LENGTH" TextBox5 = "5" '(Value of Length)
(All these textboxes are dynamically created in Groupbox "GBox1")
Instead of saving product specification in separate column. I want to save these names & values as String e.g. "WEIGHT=10;WIDTH=5;LENGTH=5" in SQL Database(TEXT OR VARCHAR field). Because we dnt want any calculations or search etc. on this. just customer requirements to book order & save in Database for future records.
Then again While calling or editing Product SPLIT the string as separate fields, String Before = Separate & string after = separate, then display all names & their corresponding values in Textboxes (as Displayed while adding) so user can edit and after changes again save as single string value.
After search I found SPLIT & JOIN functions for this purpose.
need some help in using these functions in Loop to merge string from textboxes
for each loop to read all textboxes in Groupbox
Dim ItemList As New ArrayList()
Dim PrDetails As String
For Each Ctrl As Control In GBox1.Controls
If TypeOf Ctrl Is TextBox Then
ItemList.Add(CType(Ctrl, TextBox).Text)
End If
Next
PrDetails = String.Join()
How to perform join on these array list? and again SPLIT this pattern while retrieving from Database.
Also need suggestions regarding this approach or any other way to implement. Thanks.
For this solution to work, you will need to accept the fact that there needs to be some amount of standardization to your solution. TextBox1 and TextBox3 won't work as names, so I used txtName1 and txtValue1 etc. To test this solution, make a new form, put GroupBox1, paste the code in the class and run.
Private nameTextBoxName = "txtName" ' name textbox prefix
Private valueTextBoxName = "txtValue" ' value textbox prefix
Private paramSeparator = ";" ' between sets of parameters
Private nameAndValueSeparator = "=" ' between name and value
Private xOffset = 10 ' for horizontal spacing inside the groupbox
Private yOffset = 20 ' for vertical spacing inside the groupbox
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' your example data
Dim testString = "WEIGHT=10;WIDTH=5;LENGTH=5"
' set the textboxes
setTextBoxes(testString)
' get the string from the textboxes
Dim result = getTextBoxesString()
End Sub
' call to get a string with all the data from the textboxes
Private Function getTextBoxesString() As String
Dim stringToDatabase = ""
Dim textBoxes = GroupBox1.Controls.OfType(Of Control).
Where(Function(co As Control) TypeOf co Is TextBox).
Select(Of TextBox)(Function(co As Control) CType(co, TextBox))
Dim nameTextBoxes = textBoxes.Where(Function(co As Control) co.Name.Contains(nameTextBoxName))
Dim valueTextBoxes = textBoxes.Where(Function(co As Control) co.Name.Contains(valueTextBoxName))
stringToDatabase = nameTextBoxes.Select(Of String)(
Function(nameTextBox As TextBox)
Dim valueTextBox = valueTextBoxes.
Where(Function(vtb As TextBox) vtb.Name = nameTextBox.Name.Replace(nameTextBoxName, valueTextBoxName)).
First()
Return nameTextBox.Text & nameAndValueSeparator & valueTextBox.Text
End Function).Aggregate(Function(oldValue, newValue) oldValue & paramSeparator & newValue)
Return stringToDatabase
End Function
' call to set the textboxes inside the groupbox based on the data string
Private Sub setTextBoxes(textBoxesString As String)
Dim params = textBoxesString.Split(paramSeparator)
Dim index = 1
GroupBox1.Controls.Clear()
For Each param In params
Dim nameAndValue = param.Split(nameAndValueSeparator)
Dim nameTextBox As New TextBox With
{.Name = nameTextBoxName & index.ToString(),
.Text = nameAndValue(0),
.Location = New Point(xOffset, (index - 1) * .Height + yOffset)}
Dim valueTextBox As New TextBox With
{.Name = valueTextBoxName & index.ToString(),
.Text = nameAndValue(1),
.Location = New Point(.Width + xOffset, (index - 1) * .Height + yOffset)}
GroupBox1.Controls.Add(nameTextBox)
GroupBox1.Controls.Add(valueTextBox)
index += 1
Next
End Sub

Building a collection of buttons and sorting by text

I have a collection of buttons on a panel, I want to be able to build a collection of those buttons and then sort the buttons by the text on the button. However, I am stuck. This is what I have so far, but I can't figure out how to sort.
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim btn1 As Control
Dim btnArray(0 To 3) As Button
btnArray(0) = btnAll
btnArray(1) = btnWine
btnArray(2) = btnBeer
btnArray(3) = btnNonAlcoholic
For Each btn1 In btnArray
Next
End Sub
You can use a simple manual bubble sort:
Dim Changed as Boolean = False
Do
Changed = False
For i = 0 to btnArray.Count - 2
If btnArray(i).Text > btnArray(i+1).Text Then '< > work for strings as well and they check 'position' in the alphabet. So "A" < "B" and so on
'If order is wrong, switch the two buttons
Dim temp as Button = btnArray(i+1)
btnArray(i + 1) = btnArray(i)
btnArray(i) = temp
Changed = True
End If
Next
'Do this until no more switches are necessary
Loop Until Changed = False
This will order your buttons and is reasonably fast for low numbers of buttons. You could use a list and a custom IComparer object as well and simply call List.Sort with the custom comparer.
See here for example implementations of this approach for a similar problem: http://msdn.microsoft.com/en-us/library/cfttsh47%28v=vs.110%29.aspx
Using LINQ:
btnArray = btnArray.OrderBy(Function(btn) btn.Text).ToArray

Display output on the form in VB 2010

I'm designing a windows form. I have output to be displayed on the form it self.
Tried using print, but it is not working.
How do I do that?
I'M NOT PRINTING THE FORM.
ADDED:
I need to display 3 numbers with text string next to each number.
I want to do this in a way that it shows in the form or label in the form without overwriting the previous results.
example:
3 (wrong) 1 (right) 8 (wrong)
2 (wrong) 1 (right) 5 (right)
9 (right) 1 (right) 5 (right)
ADDED:
Thanks for the help everyone. one more question and i think i'm good.
I was thinking of doing something like this inside a loop, problem is I can't add a string and an int together to make a new var:
Xnum1 = Xnum1 + 50
Xnum2 = Xnum1 + ".0F"
Ynum1 = Ynum1 + 50
Ynum2 = Ynum1 + ".0F"
In VB6 you could use the Print statement to draw to the surface of the form. In VB.NET, however, you should be using the Form.CreateGraphics method to create a new Graphics object that can be used to draw to the form's surface. For instance:
Private Sub PrintText(text As String, x As Single, y As Single)
Dim g As Graphics = Me.CreateGraphics()
g.DrawString(text, New Font("Arial", 16), New SolidBrush(Color.Black), New PointF(x, y))
End Sub
That would be the closest equivalent to using the VB6 Print statement like that.
However, I would strongly recommend using a control to display the data. It looks like for the data you need to display, a simple multi-line text box or label would be sufficient. For instance:
Private Sub AppendResult(index As Integer, right As Boolean)
If right Then
TextBox1.Text = TextBox1.Text & " " & index.ToString() & " (right)"
Else
TextBox1.Text = TextBox1.Text & " " & index.ToString() & " (wrong)"
End If
End Sub
If you want to get more fancy, you could look into using a data grid, a list box, a list view, or even a table layout control instead.
I believe that the most efficient way is to use a tableLayoutPanel with 6 columns. Add in each cell a label showing in the first cell the number, in the second the indicator for that number (right/wrong). Do the same for second and third number.(second number = third and fourth cell, third number =fifth and sixth cell)
For the next set of numbers you can add a new row with with labels in each cell.
I'll add some code to make my answer more professional.
First you add the tableLayoutPanel in your form. You size it as you like (make its width, long enough to handle the data)
You delete the lastRow and then you add columns (you want to have 6 columns). You edit the size of the columns to be Percentage =16.67%
Public Class Form1
Private rowIndex
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
For i = 0 To 4 Step 2
Dim val As Integer = 3
AddLabels(val, i, 0)
Next
For i = 1 To 5 Step 2
Dim val As String = "right"
AddLabels(val, i, 0)
Next
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
rowIndex = rowIndex + 1
Me.TableLayoutPanel1.RowStyles.Add(New RowStyle(SizeType.Absolute, 30))
Me.TableLayoutPanel1.Height = Me.TableLayoutPanel1.Height + 30
For i = 0 To 4 Step 2
Dim val As Integer = 3 'here you have to put your number
AddLabels(val, i, rowIndex)
Next
For i = 1 To 5 Step 2
Dim val As String = "right" 'here you have to put your indicator
AddLabels(val, i, rowIndex)
Next
End Sub
Private Sub AddLabels(ByVal lblValue As String, ByVal column As Integer, ByVal row As Integer)
Dim lblHeader As New Label
lblHeader.AutoSize = True
lblHeader.Margin = New Padding(0)
lblHeader.BackColor = Color.Transparent
lblHeader.TextAlign = ContentAlignment.MiddleLeft
lblHeader.Dock = DockStyle.None
lblHeader.Text = lblValue
'Put the lblHeader in the right cell
Dim lblHeaderPos As New TableLayoutPanelCellPosition(column, row)
TableLayoutPanel1.SetCellPosition(lblHeader, lblHeaderPos)
TableLayoutPanel1.Controls.Add(lblHeader)
End Sub
Let me know if you facing any problems.
Also if you don't know how many rows you will add, put the tableLyoutPanel inside a panel. Make the panel's property AutoScroll=True and then you can add infinite number of new rows.

What's the best way to create a drop-down list in a Windows application using Visual Basic?

I'd like to add a drop-down list to a Windows application. It will have two choices, neither of which are editable. What's the best control to use? Is it a combo box with the editing property set to No?
I'm using Visual Studio 2008.
I'd suggest taking a look at the Windows Vista User Experience Guide. It sounds like you might be better off with radio buttons, or, if it's an explicit on/off type of situation, using a check box. I think we'd really need more info, though.
yourComboBox.DropDownStyle = ComboBoxStyle.DropDownList
Set the DropDownStyle property to DropDownList.
See http://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.dropdownstyle(VS.80).aspx
The combobox in winforms doubles as a uneditable drop down list by changing the DropDownStyle property to "DropDownList": I don't think there is a separate drop down list control.
Create two text boxes next to each other TextBox1 and TextBox2, for TextBox2 set multiple lines and autosize.
create your dropdown list somewhere. In my example it was in a different sheet with about 13,000 entries.
Below are two functions, the first drives the input box, TextBox1. as you type, the 2nd box, TextBox2 shows the remaining valid choices. The second function, loads the first textbox if you click on a choice in the second box
In the below, cell B3 on the current sheet had to be loaded with the typed/selected answer. In my application, I only wanted to search for uppercase characters hence the UCase usage. My list data was 13302 entries in column Z
Private Sub TextBox1_Keyup(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Dim curtext As String
Dim k, where As Integer
Dim tmp As String
Dim bigtmp As String
curtext = TextBox1.Text
curtext = UCase(curtext)
TextBox1.Text = curtext
Range("b3").Value = curtext
If Len(curtext) = 0 Then
TextBox2.Visible = False
Exit Sub
End If
TextBox2.Visible = True
Application.ScreenUpdating = False
For k = 2 To 13303 ' YOUR LIST ROWS
tmp = Sheets("General Lookup").Range("Z" & k).Value ' YOUR LIST RANGE
where = InStr(1, tmp, TextBox1.Text, 1)
If where = 1 Then
bigtmp = bigtmp & tmp & Chr(13)
End If
Next
TextBox2.Text = bigtmp
Application.ScreenUpdating = True
End Sub
Private Sub TextBox2_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
If Len(TextBox2.SelText) > 0 Then
TextBox1.Text = TextBox2.SelText
Range("b3").Value = TextBox2.SelText
TextBox2.Visible = False
End If
End Sub