VB.NET dynamic controls deployment - vb.net

Below is a well working VBA code adding controls to whatever object admitting them while drawing the data from a db table. This works so well coz here I have an .Add method admitting 2 string variables defining control type and name. Cannot find anything like that on VB.Net. I can only make separate procedures for each control type. This code is not usable because I cannot build a MSForms.UserForm in abstracto. It must have a prototype build with form designer, while this on VS does not build MSForms.UserForms, but System.Windows.Forms only.
Any solution apart from making my own procedure with plenty of Selects, Ifs and similar? This still worked in VB.6 - there are historical solutions on the WEB and on this platform.
Function formFill(obj As Object, strSQL As String) As String
Dim rs As ADODB.Recordset, cntr As MSForms.Control, c As String
c = ""
On Error GoTo formFill_err
Set rs = ui_cnt.Execute(strSQL)
Do While Not rs.EOF
Set cntr = obj.Controls.Add("Forms." + rs("obj_type") + ".1", rs("obj_name"), True)
cntr.Height = rs("Height")
If Left(cntr.Name, 3) = "lbl" And cntr.Height > 32 Then cntr.WordWrap = True
cntr.Left = rs("Left")
cntr.Top = rs("Top")
cntr.Width = rs("Width")
cntr.Caption = str_convert_null(rs("caption"))
cntr.ControlTipText = str_convert_null(rs("tip"))
cntr.Font.Size = 8
cntr.Visible = True
If Left(cntr.Name, 3) = "txt" Then
cntr.AutoSize = False
Else
cntr.AutoSize = True
End If
c = c + rs("obj_type") + ";" + rs("obj_name") + ";"
rs.MoveNext
Loop
Set rs = Nothing
formFill = c
Exit Function
formFill_err:
If Err.Number = 438 Then Resume Next
End Function

Here's a sample how to create controls in Windows Form.
First, declare a container for your control setup. This is a class which replaces your ADODB.Recordset object.
Public Class MyControl
Public Property obj_type As String
Public Property obj_name As String
Public Property Top As Integer
Public Property Left As Integer
Public Property Height As Integer
Public Property Width As Integer
Public Property caption As String
Public Property tip As String
End Class
Here's a function which return an array of the class I defined before. I hardcoded the values (2 labels and 1 textbox), but you can also fetch the values from other sources like tables in database. You can replace the content of this function with any database technology for .Net, eg. ADO.Net or Entity Framework (EF).
Private Function GetMyControls() As MyControl()
Return {
New MyControl With {
.obj_type = "System.Windows.Forms.Label",
.obj_name = "lblLabel1",
.Top = 20,
.Left = 20,
.Height = 30,
.Width = 100,
.caption = "Label 1 caption",
.tip = "Label 1 tooltip"
},
New MyControl With {
.obj_type = "System.Windows.Forms.Label",
.obj_name = "lblLabel2",
.Top = 60,
.Left = 20,
.Height = 100,
.Width = 100,
.caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
.tip = "Label 2 tooltip"
},
New MyControl With {
.obj_type = "System.Windows.Forms.TextBox",
.obj_name = "txtTextbox1",
.Top = 200,
.Left = 20,
.Height = 500,
.Width = 500,
.caption = "abcdef",
.tip = "Textbox 1 tooltip"
}
}
End Function
Then create each control from the setup then add it into the form's control collections.
Private Sub BuildMyControls()
'get controls setup
Dim myControls = GetMyControls()
For Each myControl In myControls
'get control type
Dim myControlType = GetType(Control).Assembly.GetType(myControl.obj_type)
'create control
Dim cntr As Control = Activator.CreateInstance(myControlType, True)
'setting properties
With cntr
.Name = myControl.obj_name
.Top = myControl.Top
.Left = myControl.Left
.Height = myControl.Height
.Width = myControl.Width
.Text = myControl.caption
.Font = New Font(.Font.Name, 8.0F, FontStyle.Regular)
End With
'add an event handler (optional), uncomment the if statement if you want to do it for labels only
'If myControl.obj_type = "System.Windows.Forms.Label" Then
AddHandler cntr.Click, AddressOf MyControl_Click
'End If
'add new control into form's control collection
Me.Controls.Add(cntr)
Next
End Sub
Put the control creating method in the form's load event.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BuildMyControls()
End Sub
Last is optional, I add an event handler for the control click event. This method is called in the control creating method above.
Private Sub MyControl_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim cntr = DirectCast(sender, Control)
'old version (formatted string)
'Dim message = String.Format("You clicked a {0} named {1}", cntr.GetType, cntr.Name)
'new version (interpolated string)
Dim message = $"You clicked a {cntr.GetType} named {cntr.Name}"
MessageBox.Show(message)
End Sub
Full code:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BuildMyControls()
End Sub
Private Sub MyControl_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim cntr = DirectCast(sender, Control)
'old version (formatted string)
'Dim message = String.Format("You clicked a {0} named {1}", cntr.GetType, cntr.Name)
'new version (interpolated string)
Dim message = $"You clicked a {cntr.GetType} named {cntr.Name}"
MessageBox.Show(message)
End Sub
Private Sub BuildMyControls()
'get controls setup
Dim myControls = GetMyControls()
For Each myControl In myControls
'get control type
Dim myControlType = GetType(Control).Assembly.GetType(myControl.obj_type)
'create control
Dim cntr As Control = Activator.CreateInstance(myControlType, True)
'setting properties
With cntr
.Name = myControl.obj_name
.Top = myControl.Top
.Left = myControl.Left
.Height = myControl.Height
.Width = myControl.Width
.Text = myControl.caption
.Font = New Font(.Font.Name, 8.0F, FontStyle.Regular)
End With
'add an event handler (optional), uncomment the if statement if you want to do it for labels only
'If myControl.obj_type = "System.Windows.Forms.Label" Then
AddHandler cntr.Click, AddressOf MyControl_Click
'End If
'add new control into form's control collection
Me.Controls.Add(cntr)
Next
End Sub
Private Function GetMyControls() As MyControl()
Return {
New MyControl With {
.obj_type = "System.Windows.Forms.Label",
.obj_name = "lblLabel1",
.Top = 20,
.Left = 20,
.Height = 30,
.Width = 100,
.caption = "Label 1 caption",
.tip = "Label 1 tooltip"
},
New MyControl With {
.obj_type = "System.Windows.Forms.Label",
.obj_name = "lblLabel2",
.Top = 60,
.Left = 20,
.Height = 100,
.Width = 100,
.caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
.tip = "Label 2 tooltip"
},
New MyControl With {
.obj_type = "System.Windows.Forms.TextBox",
.obj_name = "txtTextbox1",
.Top = 200,
.Left = 20,
.Height = 500,
.Width = 500,
.caption = "abcdef",
.tip = "Textbox 1 tooltip"
}
}
End Function
End Class
Public Class MyControl
Public Property obj_type As String
Public Property obj_name As String
Public Property Top As Integer
Public Property Left As Integer
Public Property Height As Integer
Public Property Width As Integer
Public Property caption As String
Public Property tip As String
End Class
I don't write code for the wordwrap, autosize and tooltip.

Related

If statement not moving to the next item

I am working on a side project in VB, it is a network monitoring tool to pings a number of devices which should come back as successful or failed. I have extreme limits in programming so forgive me.
I am using buttons, a total of 34 for each device that I want to ping that returns a success or fail which will color code green(success) and red(failed) but I am sure there is a better way? Right now, my code is stuck on one button, I cant figure out how to step to the next one on the list. In my code, I have it commented out of the results I want produced which is where I am stuck on.
The text file contains all my IP addresses I want to ping separated by a comma.
Basically, when the form is running, it will display each button as green or red, depending on if the device is online or not. I want the code to loop every 2 minutes as well to keep the devices up to date. Literally a device monitoring tool. I was able to get it to work using 34 different End If statements but that is messy and a lot of work to maintain. Any assistance would be helpful.
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser("\\txt file location\device.txt")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
Dim MyLen() As String = {"Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7", "Button8", "Button9", "Button10", "Button11", "Button12", "Button13", "Button14", "Button15", "Button16", "Button17", "Button18", "Button19", "Button20", "Button21", "Button22", "Button23", "Button24", "Button25", "Button26", "Button27", "Button28", "Button29", "Button30", "Button31", "Button32", "Button33", "Button34"}
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
If My.Computer.Network.Ping(currentField) Then
MsgBox(MyLen)
'MyLen = Color.LimeGreen
Else
MsgBox(MyLen)
'MyLen.Text = "Failed"
'MyLen.BackColor = Color.Red
End If
Next
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & "is not valid and will be skipped.")
End Try
End While
End Using
enter image description here
Here is some code that takes a different approach. To try it create a new Form app with only a FlowLayoutPanel and Timer on it. Use the default names. It might be above your skill level but using the debugger you might learn something. Or not.
Public Class Form1
Private MyButtons As New List(Of Button)
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
Timer1.Enabled = False 'started later
Timer1.Interval = CInt(TimeSpan.FromMinutes(2).TotalMilliseconds) '<<<< Change >>>>
Dim path As String = "\\txt file location\device.txt"
Dim text As String = IO.File.ReadAllText(path) 'use this
''for testing >>>>>
'Dim text As String = "10.88.0.70, 10.88.0.122,192.168.0.15, 10.88.0.254, 1.2.3.4" ''for testing
''for testing <<<<<
Dim spltCHs() As Char = {","c, " "c, ControlChars.Tab, ControlChars.Cr, ControlChars.Lf}
Dim IPs() As String = text.Split(spltCHs, StringSplitOptions.RemoveEmptyEntries)
For Each addr As String In IPs
Dim b As New Button
Dim p As New MyPinger(addr)
p.MyButton = b
b.Tag = p 'set tag to the MyPinger for this address
b.AutoSize = True
b.Font = New Font("Lucida Console", 10, FontStyle.Bold)
b.BackColor = Drawing.Color.LightSkyBlue
'center text in button
Dim lAddr As String = p.Address
Dim t As String = New String(" "c, (16 - lAddr.Length) \ 2)
Dim txt As String = t & lAddr & t
b.Text = txt.PadRight(16, " "c)
b.Name = "btn" & lAddr.Replace("."c, "_"c)
AddHandler b.Click, AddressOf SomeButton_Click 'handler for button
MyButtons.Add(b) 'add button to list
Next
'sort by IP
MyButtons = (From b In MyButtons
Select b Order By DirectCast(b.Tag, MyPinger).Address(True)).ToList
For Each b As Button In MyButtons
FlowLayoutPanel1.Controls.Add(b) 'add button to panel
Next
FlowLayoutPanel1.Anchor = AnchorStyles.Bottom Or AnchorStyles.Left Or AnchorStyles.Right Or AnchorStyles.Top
Timer1.Enabled = True 'start the timer
End Sub
Private Sub SomeButton_Click(sender As Object, e As EventArgs)
'if button clicked ping it
Dim b As Button = DirectCast(sender, Button) 'which button
b.BackColor = MyPinger.UnknownColor
Dim myP As MyPinger = DirectCast(b.Tag, MyPinger) ''get the MyPinger for this
myP.DoPing() 'do the ping
End Sub
Private Async Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Timer1.Enabled = False
Dim myPs As New List(Of MyPinger)
For Each b As Button In MyButtons
b.BackColor = MyPinger.UnknownColor
Dim myP As MyPinger = DirectCast(b.Tag, MyPinger)
myPs.Add(myP)
Next
Dim t As Task
t = Task.Run(Sub()
Threading.Thread.Sleep(25)
For Each myP As MyPinger In myPs
myP.DoPing()
Next
End Sub)
Await t
Timer1.Enabled = True
End Sub
End Class
Public Class MyPinger
Public Shared ReadOnly UpColor As Drawing.Color = Drawing.Color.LightGreen
Public Shared ReadOnly DownColor As Drawing.Color = Drawing.Color.Red
Public Shared ReadOnly UnknownColor As Drawing.Color = Drawing.Color.Yellow
Private _ip As Net.IPAddress
Private _ping As Net.NetworkInformation.Ping
Public LastReply As Net.NetworkInformation.PingReply
Private Shared ReadOnly PingTMO As Integer = 2500
Private _waiter As New Threading.AutoResetEvent(True)
Public MyButton As Button
Public Sub New(IPAddr As String)
Me._ip = Net.IPAddress.Parse(IPAddr) 'will throw exception if IP invalid <<<<<
Me._ping = New Net.NetworkInformation.Ping 'create the ping
'do initial ping
Dim t As Task = Task.Run(Sub()
Threading.Thread.Sleep(25) 'so init has time
Me.DoPingAsync()
End Sub)
End Sub
Private Async Sub DoPingAsync()
If Me._waiter.WaitOne(0) Then 'only one at a time for this IP
Me.LastReply = Await Me._ping.SendPingAsync(Me._ip, PingTMO)
Dim c As Drawing.Color
Select Case Me.LastReply.Status
Case Net.NetworkInformation.IPStatus.Success
c = UpColor
Case Else
c = DownColor
End Select
Me.SetButColor(c)
Me._waiter.Set()
End If
End Sub
Public Sub DoPing()
Me.DoPingAsync()
End Sub
Private Sub SetButColor(c As Drawing.Color)
If Me.MyButton IsNot Nothing Then
If Me.MyButton.InvokeRequired Then
Me.MyButton.BeginInvoke(Sub()
Me.SetButColor(c)
End Sub)
Else
Me.MyButton.BackColor = c
End If
End If
End Sub
Public Function TheIP() As Net.IPAddress
Return Me._ip
End Function
Public Function Address(Optional LeadingZeros As Boolean = False) As String
Dim rv As String = ""
If LeadingZeros Then
Dim byts() As Byte = Me._ip.GetAddressBytes
For Each b As Byte In byts
rv &= b.ToString.PadLeft(3, "0"c)
rv &= "."
Next
Else
rv = Me._ip.ToString
End If
Return rv.Trim("."c)
End Function
End Class

AutoSize on Panel not working when creating a panel pro-grammatically

I have made a panel which I create pro-grammatically. When this panel is created I add it to the WinFrom. I then add a textbox and a label to the panel. This all works fine if I set the panel to the correct height and width however I don't want to do this as there may be more than one textbox added to the panel. The issue I'm having when I set the Autosize to True it doesn't Autosize the panel accordingly.
My code is as follows
Private Sub CreateTextBoxFieldPanel(ByVal multiLine As Boolean, ByVal textBoxName As String, ByVal labelCaption As String, tag As String, textBoxText As String)
'label plus textbox
Dim _NewPanel As Panel = CreatePanel(textBoxName, textBoxText)
Dim _NewLabel As Label = CreateLabelPanel(labelCaption)
Dim _NewTextBox As TextBox = CreateTextBoxPanel(textBoxName, multiLine, textBoxText)
_NewPanel.Controls.Add(_NewLabel)
_NewPanel.Controls.Add(_NewTextBox)
Me.Controls.Add(_NewPanel)
End Sub
Private Function CreatePanel(ByVal textBoxName As String, ByVal textBoxText As String, Optional ByVal textBoxWidth As Integer = DefaultTextBoxWidth) As Panel
'returns panel with default properties
Dim _NewPanel As New Panel
_NewPanel.Name = textBoxName
_NewPanel.Text = textBoxText
_NewPanel.Top = topForNextControl
_NewPanel.Left = 17
_NewPanel.Size = New System.Drawing.Size(0, 0)
_NewPanel.Anchor = AnchorStyles.Top Or AnchorStyles.Right
_NewPanel.TabIndex = tabIndexForNextControl
tabIndexForNextControl += 1
_NewPanel.AutoSize = True
_NewPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink
Return _NewPanel
End Function
Private Function CreateLabelPanel(ByVal LabelCaption As String) As Label
'returns label with default properties
Dim _NewLabel As New Label
_NewLabel.Text = LabelCaption
_NewLabel.Top = labelInPanel
_NewLabel.Left = 0
_NewLabel.AutoSize = True
_NewLabel.Anchor = AnchorStyles.Top Or AnchorStyles.Left
_NewLabel.TabIndex = tabIndexForNextControl
_NewLabel.BackColor = Color.Transparent
tabIndexForNextControl += 1
Return _NewLabel
End Function
Private Function CreateTextBoxPanel(ByVal textBoxName As String, ByVal multiline As Boolean, ByVal textBoxText As String, Optional ByVal textBoxWidth As Integer = DefaultTextBoxWidth) As TextBox
'returns textbox with default properties
Dim _NewTextBox As New TextBox
_NewTextBox.Name = textBoxName
_NewTextBox.Multiline = multiline
_NewTextBox.Text = textBoxText
_NewTextBox.Top = labelInPanel + textBoxInPanel
_NewTextBox.Left = 0
_NewTextBox.Width = 200
If multiline Then
_NewTextBox.Height = 20
End If
_NewTextBox.Anchor = AnchorStyles.Top Or AnchorStyles.Right
_NewTextBox.TabIndex = tabIndexForNextControl
tabIndexForNextControl += 1
Return _NewTextBox
End Function

Custom Control Display Issue

I have created this class in visual Basic it works fine but there is a slight design issue. As you can see there is this small bumb, how can I fix this? And also, how can I fix the spacing between the content Box and the selection menu.
Public Class VerticallTabControll
Inherits TabControl
Sub New()
SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.OptimizedDoubleBuffer Or ControlStyles.ResizeRedraw Or ControlStyles.UserPaint, True)
DoubleBuffered = True
SizeMode = TabSizeMode.Fixed
ItemSize = New Size(30, 170)
End Sub
Protected Overrides Sub CreateHandle()
MyBase.CreateHandle()
Alignment = TabAlignment.Left
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Dim selected As New SolidBrush(Color.FromArgb(0, 122, 204))
Dim notSelected As New SolidBrush(Color.FromArgb(63, 63, 70))
Dim B As New Bitmap(Width, Height)
Dim G As Graphics = Graphics.FromImage(B)
G.Clear(Color.FromArgb(63, 63, 70))
For i = 0 To TabCount - 1
Dim TabRectangle As Rectangle = GetTabRect(i)
If i = SelectedIndex Then
'// if tab is selected
G.FillRectangle(selected, TabRectangle)
Else
'// tab is not selected
G.FillRectangle(notSelected, TabRectangle)
End If
'Line Test
'Dim start As New Point(10, 31 * (i + 1))
'Dim ende As New Point(160, 31 * (i + 1))
'G.DrawLine(Pens.White, start, ende)
G.DrawString(TabPages(i).Text, Font, Brushes.White, TabRectangle, New StringFormat With {.Alignment = StringAlignment.Center, .LineAlignment = StringAlignment.Center})
Next
e.Graphics.DrawImage(B.Clone, 0, 0)
G.Dispose() : B.Dispose() : selected.Dispose() : notSelected.Dispose()
MyBase.OnPaint(e)
e.Dispose()
End Sub
End Class
You can try overriding the DisplayRectangle property to adjust the interior space accordingly:
Public Overrides ReadOnly Property DisplayRectangle As Rectangle
Get
Return New Rectangle(MyBase.DisplayRectangle.Left,
MyBase.DisplayRectangle.Top - 2,
MyBase.DisplayRectangle.Width + 2,
MyBase.DisplayRectangle.Height + 4)
End Get
End Property

Odd Control behavior Visual Basic Windows Form

I've dynamically added a text box to my main form on a button press:
Public Widget As UUTWidgetPanel
...
Public Sub New(ByVal UnitNo As Integer)
Me.UnitNo = UnitNo
Widget = New UUTWidgetPanel(UnitNo)
End Sub
...
Public Class UUTWidgetPanel
Public ContainerWidget As New FlowLayoutPanel
Public UnitLabel as New Label
Public CurrDrawTB As New TextBox
Public Sub New(ByVal UnitNo As Integer)
With UnitLabel
.Text = "Unit " & UnitNo.ToString
.Height = 25
.Anchor = AnchorStyles.Top + AnchorStyles.Left
.TextAlign = ContentAlignment.MiddleCenter
End With
With CurrDrawTB
.Width = 123
.Height = 25
.Text = "some text"
.ReadOnly = False
.Visible = True
.ForeColor = Color.Blue
'.Text = "CurrDrawTB"
End With
With ContainerWidget
.Controls.Add(UnitLabel)
.Controls.Add(CurrDrawTB)
I add the "ContainerWidget" FlowLayoutPanel to my main form from a method called by a button click as follows:
Private Sub AddUUT() 'adds instance of TestUnit to TestUnits, then it's controls to main form's "FlowLayoutPanel1"
Dim highestArrIdx As Integer = TestUnits.Count
TestUnits.Add(New TestUnit(highestArrIdx + 1))
FlowLayoutPanel1.Controls.Add(TestUnits.Item(highestArrIdx).Widget.ContainerWidget)
End Sub
Oddly enough, when I try to retrieve the info from CurrDrawTB, I receive an empty string, rather than the value "some text":
Dim text As String
text = Me.Widget.CurrDrawTB.Text
But writing to the textbox works:
Me.Widget.CurrDrawTB.Text = "Hi!" <--I see "Hi!" in the debugger and on the form.
Thanks in advance :)
Your CurrDrawTB Text property is being overwritten. This is a very common issue. The logic that you have posted works fine apart from this.

Serialization with collection property

Ok, so ive written a control that hosts multiple touch screen buttons. This control does this through the manipulation of a collection property marked with the attribute. Now it serializes these buttons in the InitializeComponent() sub that the designer creates for forms. However, whenever I delete the main control(the one that hosts the buttons), the designer doesnt remove the serialization code for the buttons in InitializeComponent() but even worse than that. If I copy the main control from one form and paste it into another form, the buttons aren't copied.
Here is the Code for the ButtonRow object:
Public Class ButtonRow
Inherits Control
Private WithEvents g_colTouchKeys As New TouchScreenButtonCollection
Private g_iMargin As Integer = 0
Public Sub New()
MyBase.DoubleBuffered = True
End Sub
<DefaultValue(0I)> _
Public Property ButtonMargin() As Integer
Get
Return g_iMargin
End Get
Set(ByVal value As Integer)
g_iMargin = value
End Set
End Property
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _ Editor(GetType(ButtonCollectionEditor), GetType(UITypeEditor))> _
Public ReadOnly Property Keys() As TouchScreenButtonCollection
Get
Return g_colTouchKeys
End Get
End Property
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
If MyBase.DesignMode Then
ArrangeButtons()
RenderButtons(e.Graphics)
Else
SetupButtons()
End If
End Sub
Private Sub ArrangeButtons()
Dim icl As Integer = 0
For Each B As TouchScreenKey In g_colTouchKeys
B.Top = 0
B.Left = icl
icl += g_iMargin + B.Width
Next
End Sub
Private Sub AddButtonToControlSurface()
For Each B As TouchScreenKey In g_colTouchKeys
If HasControl(B) = False Then MyBase.Controls.Add(B)
Next
End Sub
Private Sub RemoveControlsNotInCollection()
For Each C As Control In MyBase.Controls
If TypeOf C Is TouchScreenKey Then
If ButtonInCollection(DirectCast(C, TouchScreenKey)) = False Then
MyBase.Controls.Remove(C)
End If
End If
Next
End Sub
Private Function ButtonInCollection(ByVal B As TouchScreenKey) As Boolean
For Each BT As TouchScreenKey In g_colTouchKeys
If BT Is B Then Return True
Next
Return False
End Function
Private Function HasControl(ByVal C As Control) As Boolean
For Each Ct As Control In MyBase.Controls
If C Is Ct Then Return True
Next
Return False
End Function
Private Function CreateDefaultControl() As TouchScreenKey
Dim t As New TouchScreenKey(0, "Default")
t.Left = 0
t.Top = 0
t.Size = New Size(70, 70)
Return t
End Function
Private Sub RenderButtons(ByVal g As Graphics)
For Each B As TouchScreenKey In g_colTouchKeys
Dim rect As Rectangle = New Rectangle(B.Left, B.Top, B.Width, B.Height)
B.PaintButton(g, rect)
Next
End Sub
Private Sub SetupButtons()
ArrangeButtons()
RemoveControlsNotInCollection()
AddButtonToControlSurface()
End Sub
End Class
This is a sample of the InitilizeComponent() procedure after placing the ButtonRow object and adding 3 buttons to its collection:
Private Sub InitializeComponent()
Me.ButtonRow1 = New TouchPadControls.ButtonRow
Me.TouchScreenKey1 = New TouchPadControls.TouchScreenKey
Me.TouchScreenKey2 = New TouchPadControls.TouchScreenKey
Me.TouchScreenKey3 = New TouchPadControls.TouchScreenKey
Me.SuspendLayout()
'
'ButtonRow1
'
Me.ButtonRow1.Keys.AddRange(New TouchPadControls.TouchScreenKey() {Me.TouchScreenKey1, Me.TouchScreenKey2, Me.TouchScreenKey3})
Me.ButtonRow1.Location = New System.Drawing.Point(12, 12)
Me.ButtonRow1.Name = "ButtonRow1"
Me.ButtonRow1.Size = New System.Drawing.Size(321, 111)
Me.ButtonRow1.TabIndex = 0
Me.ButtonRow1.Text = "ButtonRow1"
'
'TouchScreenKey1
'
Me.TouchScreenKey1.ButtonPressGenerates = ""
Me.TouchScreenKey1.Location = New System.Drawing.Point(0, 0)
Me.TouchScreenKey1.Name = "TouchScreenKey1"
Me.TouchScreenKey1.Size = New System.Drawing.Size(80, 80)
Me.TouchScreenKey1.TabIndex = 0
Me.TouchScreenKey1.Text = "TouchScreenKey1"
'
'TouchScreenKey2
'
Me.TouchScreenKey2.ButtonPressGenerates = ""
Me.TouchScreenKey2.Location = New System.Drawing.Point(80, 0)
Me.TouchScreenKey2.Name = "TouchScreenKey2"
Me.TouchScreenKey2.Size = New System.Drawing.Size(80, 80)
Me.TouchScreenKey2.TabIndex = 0
Me.TouchScreenKey2.Text = "TouchScreenKey2"
'
'TouchScreenKey3
'
Me.TouchScreenKey3.ButtonPressGenerates = ""
Me.TouchScreenKey3.Location = New System.Drawing.Point(160, 0)
Me.TouchScreenKey3.Name = "TouchScreenKey3"
Me.TouchScreenKey3.Size = New System.Drawing.Size(80, 80)
Me.TouchScreenKey3.TabIndex = 0
Me.TouchScreenKey3.Text = "TouchScreenKey3"
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(449, 305)
Me.Controls.Add(Me.ButtonRow1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
I found the solution to this problem. All I had to do was dispose of the controls to delete them and use a ControlDesigner component to associate child controls with a main control.