list of controls for each form - vb.net

iam using vb.net 2008 ,i have 2 listboxes, one is for listing all forms name in my project and works fine, but what i need is when i click in the forms list, the other listbox should show me all the controls in the selected form name in listbox1! i have been trying and no luck.please help. this the code for listing all forms
Dim myAssembly As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly()
Dim types As Type() = myAssembly.GetTypes()
For Each myType As Object In types
If myType.BaseType.FullName.ToString.ToUpper = "SYSTEM.WINDOWS.FORMS.FORM" Then
ListBox1.Items.Add(myType.Name)
End If
Next
and this what i was trying in list2
Dim f As New Form
f.Name = ListBox1.SelectedItem.ToString
For Each c As Control In f.Controls
ListBox2.Items.Add(c.Name)
Next

OK! After several hours hunting - I hope this works in vb2008. It works in vb2015, but let's hope! The code to get a list of all forms came from another source. My problem in finding an answer has always resulted in a error in runtime casting- but finally this seems to work. Hopefully, it works for you as well.
Public Class Form1
Dim allforms() As Form
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
allforms = (From t As Type In Me.GetType().Assembly.GetTypes()
Where t.BaseType Is GetType(Form)
Let f = DirectCast(Activator.CreateInstance(t), Form)
Select f).ToArray
For Each frm As Form In allForms
ListBox1.Items.Add(frm.Name)
Next
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
For Each c As Control In allforms(ListBox1.SelectedIndex).Controls
ListBox2.Items.Add(c.Name)
Next
End Sub
End Class

Related

How to Remove a control from another Sub than the one where the control was initially created in VB .NET

I have written some code to create a PictureBox every time the code runs, which works fine.
Public Sub BtnHit_Click(sender As Object, e As EventArgs) Handles BtnHit.Click
Dim PicBoxNewCard As New PictureBox
PicBoxNewCard.Width = 114
PicBoxNewCard.Height = 166
PicBoxNewCard.SizeMode = PictureBoxSizeMode.Zoom
DrawCard(PicBoxNewCard)
Me.Controls.Add(PicBoxNewCard)
PicBoxNewCard.Location = New Point((257 + (57 * DrawnCardCounter)), 349)
But I want to be able to delete these created PictureBoxes by pressing a button, which would be in a different sub to the one that creates the Boxes.
I have googled around and have found references to creating Classes, Panels etc and have not had any success. I have found the exact code that I need to make it work, (Me.Controls.Remove(PicBoxNewCard)) but it only seems to work when executed in the same Sub.
Set the Name or Tag property and use that later when searching for the PictureBox to remove.
PicBoxNewCard.Name = $"Card{DrawnCardCounter}"
Private Sub RemoveButton_Click(sender As Object, e As EventArgs) Handles RemoveButton.Click
RemoveCardPicBox(10)
End Sub
Private Sub RemoveCardPicBox(CardNumber As Integer)
Dim delpicBox As PictureBox = Me.Controls.OfType(Of PictureBox).Where(Function(x) x.Name = $"Card{CardNumber}").FirstOrDefault
If Not delpicBox Is Nothing Then
Me.Controls.Remove(delpicBox)
End If
End Sub

How do I allow null textbox when using bindingsource Find method?

I am new to VB please assist. I have an application where I search using combo box and two textboxes. Now it is not always when all textboxes have text. Sometimes the user can search using one textbox. My problem is when I leave out a textbox that searches an integer column is using binding source find method I get : 'Input string was not in a correct format.' because the textbox is empty. My database is access database and I am searching from a gridview binding source. How can I allow txtboxIdSize to be ignored if not used? My code below:
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
TblDiesBindingSource.Filter = $"Descript LIKE '%{txtDescription.Text.Trim()}%'"
TblDiesBindingSource.Position = TblDiesBindingSource.Find("IDSIZE", txtIdSize.Text)
End Sub
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
If txtboxIdSize.TextLength > 0 then
TblDiesBindingSource.Filter = $"Descript LIKE '%{txtDescription.Text.Trim()}%'"
TblDiesBindingSource.Position = TblDiesBindingSource.Find("IDSIZE", txtIdSize.Text)
End if
End Sub

Creating arrays of controls in visual basic

Ok so here's the relevant code:
Public Shared compSelect(9) As ComboBox
Public Shared compPercent(9) As TextBox
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Data.LoadComponents("C:/Users/Jon/Documents/Visual Studio 2013/Projects/QuickBlend/QuickBlend/QuickBlend/Resources/databaseText.txt")
MsgBox("finished loading")
MainForm.compSelect = {CompSelect1, CompSelect2, CompSelect3, CompSelect4, CompSelect5, CompSelect6, CompSelect7, CompSelect8, CompSelect9, CompSelect10}
MainForm.compPercent = {CompPercent1, CompPercent2, CompPercent3, CompPercent4, CompPercent5, CompPercent6, CompPercent7, CompPercent8, CompPercent9, CompPercent10}
For Each box As ComboBox In MainForm.compSelect
box.DataSource = Data.Components
box.DisplayMember = "Name"
For Each comp As String In Data.ComponentNames
box.Items.Add(comp)
Next
MsgBox("looped")
Next
MsgBox("finished loop")
End Sub
As you can see, I've placed various MsgBoxes to see exactly whats going on. It never displays the "looped" message box. Can anybody explain to me why it's completely skipping the for loop? Been working on this for a while and got fed up with it. Thanks in advance for the help! =)
MainForm.compSelect should be Me.compSelect since this is the instance(has been filled with comboboxes) and not just the fully qualified name of the object that has not been filled.
Your problem is that you are setting the datasource for the comboBox, and then trying to add items to it. .NET does not like this, and will just exit the Sub that tries to do this, without warning (unless you have exception handling added in). Your code should be...
Public Shared compSelect(9) As ComboBox
Public Shared compPercent(9) As TextBox
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Data.LoadComponents("C:/Users/Jon/Documents/Visual Studio 2013/Projects/QuickBlend/QuickBlend/QuickBlend/Resources/databaseText.txt")
MsgBox("finished loading")
MainForm.compSelect = {CompSelect1, CompSelect2, CompSelect3, CompSelect4, CompSelect5, CompSelect6, CompSelect7, CompSelect8, CompSelect9, CompSelect10}
MainForm.compPercent = {CompPercent1, CompPercent2, CompPercent3, CompPercent4, CompPercent5, CompPercent6, CompPercent7, CompPercent8, CompPercent9, CompPercent10}
For Each box As ComboBox In MainForm.compSelect
box.DataSource = Data.Components
box.DisplayMember = "Name"
'take this stuff out, it is not needed
'For Each comp As String In Data.ComponentNames
'box.Items.Add(comp)
'Next
MsgBox("looped")
Next
MsgBox("finished loop")
End Sub

combobox not being populated

I have a windows form project with a main form. There is a textbox leave event that opens a new form. In that new forms load event i have a combobox item loop that populates the combobox items. It works perfectly fine if run on the main form but doesnt work on the second form. Why doesn't the comboboxes on the secondary form populate when that form is opened via a textbox_leave event from the main form?
this is the leave event
Private Sub tbChartTitle_Leave(sender As Object, e As System.EventArgs) Handles tbChartTitle.Leave
If Not tbChartTitle.Text = Nothing Then
frmTitleAttributes.Show()
End If
End Sub
This is the code that populates one of the comboboxes on the second form (it works if run on a combobox on the main form)
Private Sub frmTitleAttributes_Load(sender As Object, e As System.EventArgs) Handles Me.Load
InitializeComponent()
AddFonts()
End Sub
Private Sub AddFonts()
' Get the installed fonts collection.
Dim allFonts As New Drawing.Text.InstalledFontCollection
' Get an array of the system's font familiies.
Dim fontFamilies() As FontFamily = allFonts.Families
' Display the font families.
For i As Integer = 0 To fontFamilies.Length - 1
cbxTitleFonts.Items.Add(fontFamilies(i).Name)
Next
End Sub
make sure that the Load handler is hit after you show your form (use break point)
also you can try to call it in the Shown event
Private Sub frmTitleAttributes_Shown(sender as Object, e as EventArgs) _
Handles frmTitleAttributes.Shown
AddFonts()
End Sub

How to create Control Arrays in VB .NET

In VB6 there is a feature called Control Arrays, where you name controls the same name and provide them an index value. This allows you to set a value by looping through the controls and setting each value. In VB .NET I can't create a control array could someone provide me with a similar solution.
Here is a sample I wrote for something else that shows how to do something similar and shows how to do the handler as well. This makes a 10x10 grid of buttons that turn red when you click them.
Dim IsCreated(99) As Boolean
Dim Buttons As New Dictionary(Of String, Button)
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
For i As Integer = 0 To 99
Dim B As New Button
Me.Controls.Add(B)
B.Height = 30
B.Width = 40
B.Left = (i Mod 10) * 41
B.Top = (i \ 10) * 31
B.Text = Chr((i \ 10) + Asc("A")) & i Mod 10 + 1
Buttons.Add(B.Text, B)
B.Tag = i
AddHandler B.Click, AddressOf Button_Click
Next
End Sub
Private Sub Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim B As Button = sender
IsCreated(B.Tag) = True
B.BackColor = Color.Red
End Sub
Avoid using the proposed iteration approaches, you'll get a fairly random collection of controls unless your form is very simple. Simply declare the control array in your code and initialize it in the form constructor. Like this:
Public Class Form1
Private OrderNumbers() As TextBox
Public Sub New()
InitializeComponent()
OrderNumbers = New TextBox() {TextBox1, TextBox2}
End Sub
End Class
You can now treat OrderNumbers just like you could in VB6.
Maybe this is simpler. To create a control array, I put the control array declaration in a module. For example, if I have a Form with three TextBoxes and I want the TextBoxes to be part of a control array called 'mytext', I declare my control array in a module as follows:
Module Module1
Public mytext() As TextBox = {Form1.TextBox1, Form1.TextBox2, Form1.TextBox3}
End Module
And, I use the TextBoxes from the control array as follows:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
mytext(0).Text = "Hello"
mytext(1).Text = "Hi"
mytext(2).Text = "There"
End Sub
End Class
You can even loop through the control array, like you could in VB6:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
For i As Integer = 0 To 2
mytext(i).Text = i + 1
Next
End Sub
End Class
The beauty of using a module is that the TextBoxes do not even need to be in the same form.
With Winforms, you could do this:
myForm.Controls _
.OfType(Of TextBox) _
.OrderBy(Function(c) c.Name) _
.Where(Function(c) c.Name.StartsWith("somePrefix")) _
.ToArray()
On your form you would name your textboxes somePrefix1, somePrefix2, etc.
Here is an old article but it could give you more information. The top method is super easy.
Your Form, or PanelControl, or anything else that can contain child controls will have a Property called Controls.
You can loop through all of the text boxes in a control by using
'Create a List of TextBoxes, like an Array but better
Dim myTextBoxControls As New List
For Each uxControl As UserControl in MyFormName.Controls
If TypeOf(uControl) is TextBox
myTextBoxControls.Add(uControl)
End IF
Next
Now you have your iterate-able collection you can work with.
You can access a TextBoxes value with the EditValue property.
After looking at what you're trying to do a little further.
You probably want to name all of your controls with a Prefix, let's say abc for now.
For Each uxControl As UserControl in MyFormName.Controls
If TypeOf(uControl) is TextBox Then
Dim tbControl As TextBox = DirectCast(uControl, TextBox)
If tbControl.Name.StartsWith("abc") Then
tbControl.EditValue = "the Value you want to initialize"
End If
End If
Next
So this is one of the features that did not make the transition to VB.NET -- exactly :-( However, you can accomplish much of what you would have done in VB6 with two different mechanisms in .NET: Looping through the controls collection and handling control events.
Looping Through the Controls Collection
In VB.NET every form and control container has a controls collection. This is a collection that you can loop through and then do an operation on the control like set the value.
Dim myTxt As TextBox
For Each ctl As Control In Me.Controls
If TypeOf ctl Is TextBox Then
myTxt = CType(ctl, TextBox)
myTxt.Text = "something"
End If
Next
In this code sample you iterate over the controls collection testing the type of the returned object. If you find a textbox, cast it to a textbox and then do something with it.
Handling Control Events
You can also handle events over multiple controls with one event handler like you would have using the control array in VB6. To do this you will use the Handles keyword.
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged, TextBox2.TextChanged, TextBox3.TextChanged
Dim myTxt As TextBox = CType(sender, TextBox)
MessageBox.Show(myTxt.Text)
End Sub
The key here is the Handles keyword on the end of the event handler. You separate out the various controls that you want to handle and the event by using a comma. Make sure that you are handling controls that have the same event declaration. If you ever wondered what sender was for on every event well here's one of the uses for it. Cast the sender argument to the type of control that you are working with and assign it to a local variable. You will then be able to access and manipulate the control that fired the event just like you would have in VB6 if you specified and index to the array.
Using these two techniques you can replicate the functionality of control arrays in VB6. Good luck.
Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
Dim a() As Control = GetControls("textbox")
For Each c As TextBox In a
c.Text = c.Name
Next
End Sub
Private Function GetControls(typeOfControl As String) As Control()
Dim allControls As New List(Of Control)
'this loop will get all the controls on the form
'no matter what the level of container nesting
'thanks to jmcilhinney at vbforums
Dim ctl As Control = Me.GetNextControl(Me, True)
Do Until ctl Is Nothing
allControls.Add(ctl)
ctl = Me.GetNextControl(ctl, True)
Loop
'now return the controls you want
Return allControls.OrderBy(Function(c) c.Name). _
Where( _
Function(c) (c.GetType.ToString.ToLower.Contains(typeOfControl.ToLower) AndAlso _
c.Name.Contains("Box")) _
).ToArray()
End Function