Control array in VB.NET - vb.net

How do I make a control array for buttons in VB.NET? Like in Visual Basic 6.0...
Is it possible that the syntax can be like the following?
dim a as button
for each a as button in myForm
a.text = "hello"
next

Controls in .NET are just normal objects so you can freely put them into normal arrays or lists. The special VB6 construct of control arrays is no longer necessary.
So you can for example say,
Dim buttons As Button() = { Button1, Button2, … }
For Each button As Button In Buttons
button.Text = "foo"
End For
Alternatively, you can directly iterate over the controls inside a container (e.g. a form):
For Each c As Control In MyForm.Controls
Dim btt As Button = TryCast(c, Button)
If btt IsNot Nothing Then ' We got a button!
btt.Text = "foo"
End If
End For
Notice that this only works for controls that are directly on the form; controls nested into containers will not be iterated this way; you can however use a recursive function to iterate over all controls.

You can't create a control array in VB.NET, but you can archive similar functionality using the Handles keyword.
public sub Button_Click(sender as Object, e as EventArgs) Handles Button1.Click, Button2.Click, Button3.Click
'Do Something
End Sub
Yes, you can do this. But I don't think you can iterate buttons directly by giving myForm.

You create a Form and add a Layout 10 * 10, and try this,
Public Class Form1
Private NRow As Integer = 10
Private NCol As Integer = 10
Private BtnArray(NRow * NCol - 1) As Button
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
TableLayoutPanel1.Size = Me.ClientSize
For i As Integer = 0 To BtnArray.Length - 1
BtnArray(i) = New Button()
BtnArray(i).Anchor = AnchorStyles.Top Or AnchorStyles.Bottom Or AnchorStyles.Left Or AnchorStyles.Right
BtnArray(i).Text = CStr(i)
TableLayoutPanel1.Controls.Add(BtnArray(i), i Mod NCol, i \ NCol)
AddHandler BtnArray(i).Click, AddressOf ClickHandler
Next
End Sub
Public Sub ClickHandler(ByVal sender As Object, ByVal e As System.EventArgs)
MsgBox("I am button #" & CType(sender, Button).Text)
End Sub
End Class

Related

VB fires changetext event before control is loaded

I need to add some controls to a Visual Basic 2017 form programmatically. One of the controls is a textbox that needs a changetext event handler. Below is some code that accomplishes that task.
HOWEVER, the changetext event handler seems to fire right away, before the form even loads... before the textbox itself even loads! A "click" handler works fine, as expected. But changetext? Nope.
I've thrown together a simplified version to demonstrate. The line with the "DIES RIGHT HERE" comment causes the problem (not the comment, but the code to the left of it).
A textbox that is added at design time will work fine, not cause this problem, but that isn't an option.
What's causing this the changetext handler to be run early? How do I work around this?
Public Class Form1
Dim txtTest As TextBox
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim pntTextBox As Point
pntTextBox.X = 100
pntTextBox.Y = 100
txtTest = New TextBox
With txtTest
.Location = pntTextBox
.Width = 100
AddHandler txtTest.TextChanged, AddressOf txtTest_TextChanged
End With
Me.Controls.Add(txtTest)
End Sub
Private Sub txtTest_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyClass.TextChanged
Dim strTest As String
strTest = Str(txtTest.Width) ' ****** DIES RIGHT HERE
MsgBox(strTest)
End Sub
End Class
Made a few changes. Works.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For x As Integer = 1 To 2 'create multiple TB's
Dim pntTextBox As Point
pntTextBox.X = 100 * x
pntTextBox.Y = 100
Dim txtTest As TextBox = New TextBox
With txtTest
txtTest.Name = "tb_" & x.ToString
AddHandler txtTest.TextChanged, AddressOf txtTest_TextChanged
.Location = pntTextBox
.Width = 100
End With
Me.Controls.Add(txtTest)
Next
End Sub
Private Sub txtTest_TextChanged(ByVal sender As Object,
ByVal e As System.EventArgs) 'no handler at design time
Dim tb As TextBox = DirectCast(sender, TextBox)
Dim strTest As String
strTest = tb.TextLength.ToString
Debug.WriteLine("{0} {1}", tb.Name, strTest) 'put breakpoint here
End Sub
End Class

Dynamically create multiple button and assign single click and double click comand

I created multiple button dynamically inside a panel based on multiple click on add button. Each button deletes When I click on it.
I want each button to delete when I single click on it, and say hello when I double click. Thank you.
I have tried using this code to delete which works fine, but I cannot figure how to assign seperate code to display hello when I double click or right click on it without affecting delete aspect of it.
Private Sub btnDynamic_Click(ByVal sender As Object, ByVal e As EventArgs)
'Reference the Button which was clicked.
Dim button As Button = CType(sender, Button)
'Determine the Index of the Button.
Dim index As Integer = Integer.Parse(button.Name.Split("_")(1))
'Find the TextBox using Index and remove it.
FlowLayoutPanel1.Controls.Remove(FlowLayoutPanel1.Controls.Find(("btnDynamic_" & index), True)(0))
'Remove the Button.
FlowLayoutPanel1.Controls.Remove(button)
'Rearranging the Location controls.
For Each btn As Button In FlowLayoutPanel1.Controls.OfType(Of Button)()
Dim controlIndex As Integer = Integer.Parse(btn.Name.Split("_")(1))
If (controlIndex > index) Then
Dim btn1 As Button = CType(FlowLayoutPanel1.Controls.Find(("btnDynamic_" & controlIndex), True)(0), Button)
btn1.Top = (btn.Top - 25)
'txt.Top = (txt.Top - 25)
End If
Next
End Sub
Here is the create button code:
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
If TextBox1.Text = "" Then
Exit Sub
End If
Dim count As Integer = Form2.FlowLayoutPanel2.Controls.OfType(Of Button).ToList.Count
Dim button As Button = New Button
button.Size = New System.Drawing.Size(28, 21)
button.Name = "btnDynamic_" & (count + 1)
button.Text = TextBox1.Text
AddHandler button.Click, AddressOf Me.button_click
Form2.FlowLayoutPanel2.Controls.Add(button)
End Sub
You have to enable DoubleClick option first.
You do so with:
Public Class DoubleClickButton
Inherits Button
Public Sub New()
SetStyle(ControlStyles.StandardClick Or ControlStyles.StandardDoubleClick, True)
End Sub
End Class
Then create a "DoubleClick" and "SingleClick" methods and assign them to (new custom) buttons when you are creating them.
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
For x = 0 To 2
Dim ButtonX As New DoubleClickButton
ButtonX.Text = x
AddHandler ButtonX.MouseClick, AddressOf SingleClickE
AddHandler ButtonX.MouseDoubleClick, AddressOf DoubleClickE
FlowLayoutPanel1.Controls.Add(ButtonX)
Next
End Sub
Private Sub SingleClickE(sender As Object, e As MouseEventArgs)
Debug.Print("Hello!")
End Sub
Private Sub DoubleClickE(sender As Object, e As MouseEventArgs)
FlowLayoutPanel1.Controls.Remove(sender)
End Sub
Thank you all for attempting to answer my question. I have been able to figure it out. I intend firing diffrent events with dynamically created buttons using single click, double click or right click. I ended up using single and right click command. Though would have prefered double click, but it is ok. Below is the code.
'Create buttons
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For i As Integer = 1 To 5
Dim button As New Button
button.Text = i
AddHandler button.Click, AddressOf SingleClickE
AddHandler button.MouseDown, AddressOf RightClickE
FlowLayoutPanel1.Controls.Add(button)
Next
End Sub
'Fire it up with single click
Private Sub SingleClickE(sender As Object, e As MouseEventArgs)
Dim button As Button = CType(sender, Button)
MsgBox("Hello World")
End Sub
'Fire it up with Right Click
Private Sub RightClickE(sender As Object, e As MouseEventArgs)
Dim button As Button = CType(sender, Button)
If e.Button = MouseButtons.Right Then
FlowLayoutPanel1.Controls.Remove(button)
End If
End Sub

How to disable and get name for control in FlowLayoutPanel from ContextMenuStrip in VB.Net

My program contains buttons in a FlowLayoutPanel.
I want to disable any button when right click on it and click "Disable" in the ContextMenuStrip.
My code is:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For i As Integer = 0 To 30
Dim btn As New Button
btn.Name = i
btn.Text = i
btn.ContextMenuStrip = ContextMenuStrip1
FlowLayoutPanel1.Controls.Add(btn)
Next
End Sub
End Class
declare a public varibale for keeping a control
public ctrl as button = nothing
you can create a right click by putting this code on mouse down...
If e.Button <> Windows.Forms.MouseButtons.Right Then Return
Dim cms = New ContextMenuStrip
ctrl = sender
Dim item1 = cms.Items.Add("Disable")
item1.Tag = 1
AddHandler item1.Click, AddressOf Disable
end if
and in the diable sub you can code like this...
Private Sub Disable()
ctrl.enabled = false
End Sub

Visual Indication of Focus and Adding Click Event To all TextBoxes

I'm working on a program wherein I have around 400 Text Boxes and I need to program an effect to make them show that they have focus. I can get the visual part down (Unless someone knows how to add a soft blue outline to a text box in VB), but I'm having trouble with creating GotFocus and LostFocus events that handle all of my Text Boxes at once. I've tried
Dim txtBox = Me.Controls.OfType(Of TextBox)
Private Sub TextBox_GotFocus(sender As Object, e As EventArgs) Handles txtBox.GotFocus
But I get a "Must have WithEvents variable" error which I don't quite understand how to fix. I've tried
Public Sub txtBoxGotFocusHandler(ByVal sender As Object,
ByVal e As System.EventArgs)
For Each txtBox As TextBox In Me.Controls 'References all text boxes in form
If txtBox.Focus = True Then
txtBox.BackColor = Color.Black
End If
Next
And I've tried a few other somewhat related things I've seen around the internet, but to no avail. Any help would be appreciated
You can make your app at runtime with any controls. You could query the layout of your app from SQL and from a simple change your app layout changes.
Private FocusRectangle As System.Drawing.Graphics
Private OldRectangle As System.Drawing.Graphics
Private MyTextBoxes As New List(Of TextBox)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MyTextBoxes.Clear()
For xcount = 0 To 399
MyTextBoxes.Add(New TextBox)
With MyTextBoxes.Item(xcount)
.Name = "MyTextBoxes" & (xcount + 1).ToString
.Text = ""
.Location = New Point(0, 0)
.Size = New Size(50, 13)
.Visible = True
AddHandler .GotFocus, AddressOf MyTextBoxes_GotFocus
AddHandler .LostFocus, AddressOf MyTextBoxes_LostFocus
End With
Me.Controls.Add(MyTextBoxes.Item(xcount))
'add them to a panel....
'Panel1.Controls.add(MyTextBoxes.Item(xcount))
Next
End Sub
Sub MyTextBoxes_GotFocus(sender As Object, e As EventArgs)
Dim ThisTextBox As TextBox = DirectCast(sender, TextBox)
Dim xPen As New System.Drawing.Pen(Color.LightBlue)
FocusRectangle = Me.CreateGraphics()
FocusRectangle.DrawRectangle(xPen, ThisTextBox.Location.X - 1, ThisTextBox.Location.Y - 1, ThisTextBox.Size.Width + 1, ThisTextBox.Size.Height + 1)
OldRectangle = FocusRectangle
End Sub
Sub MyTextBoxes_LostFocus(sender As Object, e As EventArgs)
Dim ThisTextBox As TextBox = DirectCast(sender, TextBox)
OldRectangle.Dispose()
End Sub
Private Sub Form1_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
MyTextBoxes.Item(0).Focus()
End Sub
If you created your form with the Designer, the WithEvents is added for you automatically.
If you are declaring 400 text boxes as Private fields, you would declare them as Private WitheEvents txtBox As TextBox
If you're creating the text boxes programatically and adding them to a collection of textboxes or something, then you can't do WithEvents.
But all WithEvents does is allow you to add Handeles TextBox.SomeEvent to a function. Instead you can do this:
Dim txtBox As New TextBox
...
AddHandler txtBox.GotFocus, AddressOf txtBoxGotFocusHandler
Me.Controls.Add(txtBox)

How to customize the click event of dynamically created buttons from string array?

Here is the code I have:
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddNewButton()
End Sub
Public Sub AddNewButton()
Dim buttonTop As Integer = 100
For Each item As String In Globals.candidates
Dim btn As New System.Windows.Forms.Button()
Dim Location As New Point(100, (buttonTop + 20))
btn.Location = Location
btn.Text = item
btn.Width = 150
AddHandler btn.Click, AddressOf Me.buttonClick
Me.Controls.Add(btn)
buttonTop += 20
Next
End Sub
Private Sub buttonClick()
Dim result As Integer = MessageBox.Show(String.Format("Did you select {0} ?", ???????????), "Confirmation", MessageBoxButtons.YesNo)
If result = DialogResult.Yes Then
MessageBox.Show("Yes pressed")
Else
MessageBox.Show("No pressed")
End If
End Sub
End Class
Globals.candidates is a global string array variable that holds a name "LastName, FirstName" and when the form is loaded I call the AddNewButton() Sub and it creates buttons for each item in the string array. No problem.
If you see in my code the "??????????" section, I don't know how to reference the dynamically created buttons's text so that I can display the proper "Did you select thisButton.text" properly.
Any help is appreciated.
Thanks!
EDIT:
Code changed as per suggestions: (Working)
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddNewButton()
End Sub
Public Sub AddNewButton()
Dim buttonTop As Integer = 100
For Each item As String In Globals.candidates
Dim btn As New System.Windows.Forms.Button()
Dim Location As New Point(100, (buttonTop + 20))
btn.Location = Location
btn.Text = item
btn.Width = 150
AddHandler btn.Click, AddressOf Me.buttonClick
Me.Controls.Add(btn)
buttonTop += 20
Next
End Sub
Private Sub buttonClick(sender As Object, e As EventArgs)
Dim btn As Button = DirectCast(sender, System.Windows.Forms.Button)
Dim result As Integer = MessageBox.Show(String.Format("Did you select {0} ?", btn.Text), "Confirmation", MessageBoxButtons.YesNo)
If result = DialogResult.Yes Then
MessageBox.Show("Yes pressed")
Else
MessageBox.Show("No pressed")
End If
End Sub
End Class
You need to put the proper signature on your event handler:
Private Sub buttonClick(sender As Object, e As EventArgs)
Then, you can use the sender object (which will be whichever button was clicked)
Dim button As Button = DirectCast(sender, System.Windows.Forms.Button)
Dim result As Integer = MessageBox.Show(String.Format("Did you select {0} ?", button.Text), "Confirmation", MessageBoxButtons.YesNo)
To get a reference to the button clicked you need to declare the event handler of the button click with the two parameters that are passed to it by the form engine.
Private Sub buttonClick(sender as Object, e as EventArgs)
Now, this correct event handler receives a parameter named sender that is the control reference to the button clicked. You could cast it to a button and then extract the Text property
Private Sub buttonClick(sender as Object, e as EventArgs)
Dim btn = DirectCast(sender, System.Windows.Forms.Button)
if btn IsNot Nothing then
Dim result As Integer = MessageBox.Show(String.Format("Did you select {0} ?", btn.Text), "Confirmation", MessageBoxButtons.YesNo)
If result = DialogResult.Yes Then
MessageBox.Show("Yes pressed")
Else
MessageBox.Show("No pressed")
End If
End If
End Sub
This should be enough in this simple case where you have just a string data, but, if you need to associate a more complex object (like an instance of a Person class for example) you could use the Tag property of every dynamically added button to store there a reference to the instance of the class
As a side note, your code works also without the declaration of the two parameters because you have the Option Strict configuration set to OFF. This is a bad practice because it introduces subtle errors in you parameters usage and in automatic conversions of type. If you are just starting with a new project remember to set its property Option Strict to ON