For this you can use a Panel control. To make it scrollable just set the autoscroll property to true. To add a control dynamically when you click a button or any other event, just create the controls and then add it to the controls property of the panel control. You can even add it straight into the windows forms by using Me.Controls.Add().
I think the best controls to use for this would be either the Panel or FlowLayoutPanel. When the button or some event fires just create a new control like such
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim newButton As New Button With {.Location = New Point(0, 20), .Text = "SomeButton"}
'be sure to set the location of the new control
Dim newAnotherButton As New Button With {.Location = New Point(0, 60), .Text = "Other button"}
'you can add a handler for a event on that new control too using
AddHandler newButton.Click, Sub() MsgBox("Something happend") 'sub using Lambda Expression
'alt method
AddHandler newAnotherButton.Click, AddressOf someMethod
'instead of 'Me' you would have the panelcontrol name there if thats what your using
Me.Controls.Add(newButton)
Me.Controls.Add(newAnotherButton)
End Sub
Sub someMethod(ByVal sender As Object, ByVal e As EventArgs)
MsgBox("Something else..")
End Sub
Create the controls and add them to the panel, flowlayout, form or whatever. Use a loop if you need to create more than one. Be sure to change the location of the new control so that it is not over or ontop of the previous control.
And Heres some sample code. I used a table layout for each row in this example.
'Note: pnDynamicControls is a Panel control with the autoscroll property set to true
'This method can be called when a button is clicked or something
Sub addTextBoxRow()
Dim strText() As String = {"FirstName", "LastName", "PhoneNumber"}
Dim tabRow As New TableLayoutPanel With {.RowCount = 1, .ColumnCount = strText.Length, .Height = 20, .Width = 240}
For cols As Integer = 0 To tabRow.ColumnCount
tabRow.ColumnStyles.Add(New ColumnStyle(SizeType.Absolute, 80.0F))
Next
For Each txtMsg As String In strText
Dim txtBox As New TextBox With {.Text = txtMsg, .Size = New Size(40, 20), .Anchor = AnchorStyles.None, .Dock = DockStyle.Fill}
tabRow.Controls.Add(txtBox)
Next
If pnDynamicControls.Controls.Count > 0 Then
If pnDynamicControls.Controls.Item(pnDynamicControls.Controls.Count - 1).GetType = GetType(TableLayoutPanel) Then
Dim previousTab As TableLayoutPanel = CType(pnDynamicControls.Controls.Item(pnDynamicControls.Controls.Count - 1), TableLayoutPanel)
tabRow.Location = New Point(0, previousTab.Location.Y + 25)
End If
End If
pnDynamicControls.Controls.Add(tabRow)
End Sub
Yeah i agree, i didn't feel like writing code for that earlier, but heres an example using just one tablelayout which makes more more sense like you said.
I wrote a class that inherited TableLayoutPanel, of course thats not necessary, i just like it better this way. Heres the rewritten code.
Public Class Form1
Private tabLayout As TableLayout_DynamicControls
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
tabLayout = New TableLayout_DynamicControls(3, 30)
tabLayout.Width = pnDynamicControls.Width - 20
pnDynamicControls.Controls.Add(tabLayout)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim columnTexts() As String = {"FirstName", "LastName", "PhoneNumber"}
Dim newRowControls As New List(Of Control) 'felt this was easier to use compared to a fixed array which would need a loop with element numbers
For Each columnText As String In columnTexts
Dim txtBox As New TextBox With {.Text = columnText}
newRowControls.Add(txtBox)
Next
tabLayout.AddRow(newRowControls.ToArray())
End Sub
End Class
''' <summary>
''' Creates a TableLayout with a set number of columns, and row height with no rows. A row of controls can be added using AddRow.
''' Column sizes are set to percent to fit all columns evenly.
''' </summary>
Class TableLayout_DynamicControls
Inherits TableLayoutPanel
Property RowHeight As Integer
Sub New(ByVal colCount As Integer, ByVal rowHeight As Integer)
MyBase.New()
MyBase.Height = 0
MyBase.ColumnCount = colCount
Me.RowHeight = rowHeight
MyBase.ColumnStyles.Clear()
For count As Integer = 0 To colCount
MyBase.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, CSng((1 / colCount))))
Next
End Sub
Sub AddRow(ByVal ParamArray controls() As Control)
If controls.Length = MyBase.ColumnCount Then
MyBase.Height += RowHeight
MyBase.RowStyles.Add(New RowStyle(SizeType.Absolute, RowHeight))
MyBase.Controls.AddRange(controls)
For Each Control As Control In controls
Control.Dock = DockStyle.Fill
MyBase.SetRow(Control, MyBase.RowCount - 1)
Next
Else
Throw New NotSupportedException("There must be one control for each column. Greater or Less than is not supported.")
End If
End Sub
End Class
Thanks JohH, i didnt know addrange did that. i edited and removed two lines of code from the previous post.
I played with the autosize property a bit,and i think leaving that optional does the trick because if it is set to true it overrides the width that is set as well.
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.