Most efficient way to refer to multiple controls. IE: the multi-WITH - vb.net

I have had a little look around and cannot seem to find an easy way to refer to multiple controls in stuff like an IF statement, or to set a property to multiple controls etc. (IF exists = true!)
The 'shortcut'if you like; would best be described in illegal code such as:
Public Sub BreakCompiler()
if string.IsNullOrEmpty(Textbox1.text, textbox2.text, textbox3.text) Then .....
'As opposed to
If String.IsNullOrEmpty(PartNumTextBox.Text) Or _
String.IsNullOrEmpty(PartNameTextBox.Text) Or _
String.IsNullOrEmpty(PartGRNTextBox.Text) Or_
String.IsNullOrEmpty(SerialNumTextBox.Text) Then
'Warn user
Else
'do nofin.
End If
Or even more outlandish:
WITH Textbox1.text, textbox2.text, textbox3.text
.ReadOnly = true
END WITH
End sub
The idea is to prevent having to run 3 if statements, or whatever, that basicaly do the same thing to 3 different objects...etc.. etc. Similar to a handler for multiple events that can be separated by a ','.
Im aware of looping through controls (IE for each control in groupbox.controls for eg) but that wouldn't quite achieve what I'm after here. (Say you wanted to skip a couple?)
Just thought id check the collective wisdom.

As far as I know, there isn't anything similar to a handler for control properties in if statements.
You either have to do them separately (or add them all into an array), or, as you mentioned, go through a subset within another control.
However, one thing you can do (say you only wanted to change a certain type of control), is this:
For Each tb As TextBox In Me.Controls.OfType(Of TextBox)
'do stuff here
Next
Another option is to create a Sub that will make the changes for you, and then pass each into the Sub.
Private Sub changeTextBox(tBox as TextBox)
'make changes here
End Sub

You want to process a variable length collection of some type of object. One way to do this is to write helper methods that have an argument decorated with ParamArray keyword.
Public Shared Function AnyIsNullOrEmpty(ParamArray controls As Control()) As Boolean
Dim ret As Boolean
For i As Int32 = 0 to controls.GetUpperBound(0)
ret = String.IsNullOrEmpty(controls(i).Text)
If ret then Exit for
Next
Return ret
End Function
Public Shared Sub SetTBReadOnlyProperty(value As Boolean,ParamArray textboxes As TextBox())
For i As Int32 = 0 to textboxes.GetUpperBound(0)
textboxes(i).ReadOnly=value
Next
End Sub
Possible usage:
Private Sub DemoUsage
If AnyIsNullOrEmpty(TextBox1,TextBox3,TextBox4) then
' at least one is empty
Else
' all have value
End If
SetTBReadOnlyProperty(True,TextBox1,TextBox3,TextBox4)
End Sub

The newer versions of .NET allow you to use the .ForEach Linq extension on a List object. If you build a e.g. a List(Of TextBox) you can use .ForEach with an anonymous method to quickly iterate the controls in the List and manipulate properties and so forth. It's still a loop - but in a much more compact form. You can be selective about which controls are in a List, and have multiple Lists etc.
Here's an example:
Public Class Form1
Private _BoxList As New List(Of TextBox)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
_BoxList.ForEach(Sub(tb As TextBox) tb.Enabled = Not (tb.Text = String.Empty))
End Sub
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
_BoxList.Add(Me.TextBox1)
_BoxList.Add(Me.TextBox2)
_BoxList.Add(Me.TextBox3)
End Sub
End Class
That's just 3 TextBoxs and a Button on a vanilla form:

For the particular example I was working on when I thought "There must be a better way" Something like this works perfectly.
It might be easier if trying to do multiple non type specific operations on different things. (Thanks #Sastreen and #the_lotus)
Private Sub Validate_PartDetails() Handles PartNumTextBox.TextChanged, PartNameTextBox.TextChanged, PartGRNTextBox.TextChanged, SerialNumTextBox.TextChanged
For Each tb As TextBox In BasicDetailsCustomGroupBox.Controls.OfType(Of TextBox)
If tb.Tag = "notnull" Then
If String.IsNullOrEmpty(tb.Text) Then
tb.BackColor = Color.MistyRose
Else
tb.BackColor = Control.DefaultBackColor
End If
End If
If tb.Tag = "notnumeric" Then
If not(isnumeric(tb.Text)) Then
tb.BackColor = Color.MistyRose
Else
tb.BackColor = Control.DefaultBackColor
End If
End If
Next
End Sub
Thanks guys.

Related

Is there any way to create a global function to clear TextBoxes?

I was wondering if there is any way to create a class with a global function/method/sub that upon
calling it will clear some of the textboxes of the form. How can i handle the different number of textboxes
each forms has?
The current code clears only the pre-defined 2 boxes. Thank you.
Public Class ClearElements
Public Sub CLEAR_TEXT(ByVal text1 As TextBox, ByVal text2 As TextBox)
text1.Clear()
text2.Clear()
End Sub
End Class
There are many ways to do it.
You can add the TextBoxes to a List, and clear each item in the list
Private ReadOnly someOfTheTextBoxes As New List(Of TextBox)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
someOfTheTextBoxes.Add(TextBox1)
someOfTheTextBoxes.Add(TextBox2)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For Each t In someOfTheTextBoxes
t.Clear()
Next
End Sub
Or make this method
Public Sub CLEAR_TEXT(textboxes As IEnumerable(Of TextBox))
For Each t In textboxes
t.Clear()
Next
End Sub
and call it with your list of TextBoxes
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
CLEAR_TEXT(someOfTheTextBoxes)
End Sub
or make an array on the spot and pass it in
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
CLEAR_TEXT({TextBox1, TextBox2})
End Sub
If you are interested in recursion at all, here are some extensions I have which could help
Module Extensions
<Runtime.CompilerServices.Extension>
Public Function ChildControls(parent As Control) As IEnumerable(Of Control)
Return ChildControls(Of Control)(parent)
End Function
<Runtime.CompilerServices.Extension>
Public Function ChildControls(Of TControl As Control)(parent As Control) As IEnumerable(Of TControl)
Dim result As New List(Of TControl)
For Each ctrl As Control In parent.Controls
If TypeOf ctrl Is TControl Then result.Add(CType(ctrl, TControl))
result.AddRange(ctrl.ChildControls(Of TControl)())
Next
Return result
End Function
<Runtime.CompilerServices.Extension>
Public Function ForEach(Of TSource)(source As IEnumerable(Of TSource), action As Action(Of TSource)) As IEnumerable(Of TSource)
For Each item As TSource In source
action(item)
Next item
Return source
End Function
<Runtime.CompilerServices.Extension>
Public Function ForEach(Of TSource)(source As IEnumerable(Of TSource), action As Action(Of TSource, Integer)) As IEnumerable(Of TSource)
For i As Integer = 0 To source.Count() - 1
action(source.ElementAt(i), i)
Next
Return source
End Function
End Module
Clear all textboxes recursively
Me.ChildControls(Of TextBox).ForEach(Sub(t) t.Clear())
Or ForEach on your list
someOfTheTextBoxes.ForEach(Sub(t) t.Clear())
We have this:
You could recursively go through all the controls in the form and in case of type = Textbox clear it.
But then the plot thickens:
I've done that before. It clears all the boxes of the form. I am talking about the case where some boxes have to be untouched and some to cleared.
The solution here is two parts. First, create the recursive method as suggested like this:
Public Sub ClearText(root As Control)
For Each ctrl As Control In Root.Controls
If TypeOf ctrl Is TextBox Then ctrl.Text = String.Empty
ClearText(ctrl)
Next ctrl
End Sub
or this:
Public Sub ClearText(root As IEnumerable(Of Control))
For Each ctrl As Control In root
If TypeOf ctrl Is TextBox Then ctrl.Text = String.Empty
ClearText(ctrl.Controls)
Next ctrl
End Sub
Second, on your form, use a container like Panel, GroupBox, FlowLayoutPanel, etc for the TextBox controls you need to clear. The key is all of the TextBox controls you need to clear — and none of the ones you want to keep — should be in same common container. Once that is done, you can pass the container to one of the above methods. If this messes with your layout, you can have a small number of containers for sets of controls on different areas of the form and call the function just a few times.
Remember, Panel controls can be styled to leave no visible artifacts on the parent form at all, and used entirely for logical groupings. The second version of the method above will also allow you to create arrays or lists of the controls (or control containers) you care about.
Another way to control this is to inherit a custom control from TextBox. You don't even need to change anything. All that matters is the control is now a different type from a regular textbox, and so the recursive method can target your new control type instead of textbox.
I'm using For in some cases.
First is to know for what do you need Textboxes or any component.
Second is to know if Textboxes (or any other component) will be inside Form (root) or inside others components like panels, groupoxes, tabPages… and if them will be inside of others.
Example1: Form – GroupBox(x) – TabControl(y) – TabPage(z) – TextBox(n)
Example2: Form --- TextBox(x)
Example3: Form – GroupBoox(x) – Panel(y) – TextBox(n)
Etcetera.
You may to create some anidated subs/functions to complete something more elaborated. There are two important things:
Path of the component (see previous examples)
Number of the component. If you follow Example3, maybe could be this:
Form1 – GroupBox2 – Panel1 – TextBox3
Important: These are names of the components, and you need must be enumerated all of them.
The easy way to do what you are asking is:
Public Sub CountTextBoxesAndClear(ByVal FormName As String, Optional ByVal myObject As Object = Nothing)
Dim ArrayTextBoxName() As String
Dim myTextBox As New TextBox
Dim nTBOX As Integer
'Path of component
If myObject = Nothing Then myObject = My.Application.OpenForms.Item(FormName)
'Bucle
For i As Integer = 0 To myObject.Controls.Count - 1
If myObject.Controls(i).GetType Is GetType(TextBox) Then
'Counting
nTBOX += 1
'Redim array
ReDim Preserve ArrayTextBoxName(nTBOX)
'Get Component
ArrayTextBoxName(nTBOX) = "TextBox" & nTBOX
'Get Path
myTextBox = myObject.Controls.Item(ArrayTextBoxName(nTBOX))
'myTextBox = myObject.Controls.Item("TextBox" & nTBOX) '<< the same of above line
Try
'Clear TextBoxes
myTextBox.Clear()
Catch ex As NullReferenceException
'A TextBox is Null, no error message
End Try
End If
Next
End Sub
FormName is the name of Form, with quotes, for example “Form1”.
myObject is the object that contains textboxes, if Textboxes are inside of a Panel named Panel1, you must write Panel1 (without quotes).
Try/Catch: Maybe you need to have Textbox1, TextBox2, Textbox4, Textbox5, AnotherTextBox1, AnotherTextBox2.
And you call your sub:
CountTextBoxesAndClear("Form1")
If TextBoxes are into a Panel named Panel1:
CountTextBoxesAndClear("Form1", Panel1)
You must to have the total of textboxes but only clear (or do any action) only for TextBoxes named TextBox[x].
Try/Catch manage the error because TextBox3 does not exist. However, the correct way is Textbox1, TextBox2, Textbox3, Textbox4, AnotherTextBox1, AnotherTextBox2 and put limits in your sub/function.
For example:
Public Sub CountTextBoxesAndClear(ByVal FormName As String, Optional ByVal myObject As Object = Nothing, Optional byval start as integer = 0, Optional byval finish as integer = 0)
[…tracatra…]
For i As Integer = start To finish
[…tratra…]
Next
End Sub
And this is how to call:
CountTextBoxesAndClear("Form1", Nothing, 1, 4)
And now, you can investigate a little bit about how create subs/functions to know correct paths of components, and get contents and properties of TextBoxes, Labels, Comboboxes, checkboxes…
Additional info:
If you are working in VisualStudio, you know that if you change a name of component, all of code is changed automatically. This is a big problem if you are using start/finish vars as numbers because, you must to change manually all start/finish values in functions when you need to add/remove or move positions, for example:
CountTextBoxesAndClear("Form1", Nothing, 8, 12)
Now you need to add a new TextBox just in the eight position and move one. Your sub looks like this:
CountTextBoxesAndClear("Form1", Nothing, 9, 13)
You can create a simply function that convert the name of the component to integer (this function is only for two digits (0 to 99):
Public Function ObjToInt(ByVal IntObject As Object) As Integer
If IntObject IsNot Nothing Then
Dim ref As Integer = Val(IntObject.Name.Substring(IntObject.Name.Length - 2))
If ref = 0 Then
ref = Val(IntObject.Name.Substring(IntObject.Name.Length - 1))
End If
Return ref
Else
Return 0
End If
End Function
And your sub may be written like this:
CountTextBoxesAndClear("Form1", Nothing, ObjToInt(TextBox9), ObjToInt(TextBox13))
Thanks for your awesome solutions.
I finally figured it out using ParamArray
Public Sub CLEAR_TEXTBOXES(ParamArray arr_textboxes() As TextBox)
For Each textbox As TextBox In arr_textboxes
textbox.Clear()
Next
End Sub
Then i call class using whatever textbox i want,
CLS_CLEAR_TEXTBOX.CLEAR_TEXTBOXES(TextBox1, TextBox2, Textbox7)
It's more shorter method.
Use ParamArray and Linq.
Public Sub CLEAR_TEXT(ParamArray text As TextBox())
text.ToList().ForEach(Sub(s) s.Clear())
End Sub

How to pass a form, object or data to a second form

I have created 2 forms.
The first one is the button that you want to back up.
In the second there are paths that can be modified.
How to make a reference that after pressing the "backup" button will get a path of 2 forms.
The path is saved when I closed form2
I know how to do it in one form but unfortunately I can not refer to another form.
Source of Form 2:
Private Sub Browser_from1_Click(sender As Object, e As EventArgs) Handles Browser_from1.Click
Dim FolderBrowserDialog1 As New FolderBrowserDialog
FolderBrowserDialog1.ShowDialog()
TextBox1from.Text = FolderBrowserDialog1.SelectedPath
If Browser_from1.Text <> "" And TextBox1from.Text <> "" Then
Backup.StartCopy.Enabled = True
End If
End Sub
Private Sub Browser_to1_Click(sender As Object, e As EventArgs) Handles Browser_to1.Click
Dim FolderBrowserDialog1 As New FolderBrowserDialog
FolderBrowserDialog1.ShowDialog()
TextBox2to.Text = FolderBrowserDialog1.SelectedPath
If Browser_to1.Text <> "" And TextBox2to.Text <> "" Then
Backup.StartCopy.Enabled = True
End If
End Sub
Private Sub TextBox1from_TextChanged(sender As Object, e As EventArgs) Handles TextBox1from.TextChanged
End Sub
Private Sub save_settings_Click(sender As Object, e As EventArgs) Handles save_settings.Click
My.Settings.pathmem = TextBox2to.Text
My.Settings.pathmem1 = TextBox1from.Text
My.Settings.Save()
End Sub
Private Sub setting_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TextBox1from.Text = My.Settings.pathmem1
TextBox2to.Text = My.Settings.pathmem
End Sub
End Class
You dont want to create a reference to a form - that would (or could) create a whole new form. You want to hold onto the form reference.
This is done by passing a reference to the forms, but the talk of one form fiddling with the controls on another form is a bad idea because it breaks encapsulation. But forms are classes (it says so at the top of each one), so you can add Properties and Methods (Sub and/or Functions) to facilitate passing information back and forth.
Method One - Passing a Form Reference
The simplest way is to pass whatever the other form needs in the constructor:
' form 1 / "main" form / form to return to
Dim frm As New Form6(Me)
frm.Show()
Me.Hide()
In order for this to work, you need to modify the constructor (Sub New) on the destination form:
Private frmReturnTo As Form
Public Sub New(f As Form)
' This call is required by the designer.
InitializeComponent()
frmReturnTo = f
End Sub
It is best not to create your own constructor until you are familiar with them. Use the drop downs at the top of the code window: from the left pick the form name; from the right, select New. The designer adds required code to them which must not be changed.
Do not add any code before the InitializeComponent() call at least until you are familiar with the life cycle of a form. The form and its controls do not exist until that runs.
To return to the "main" form:
If frmReturnTo IsNot Nothing Then
frmReturnTo.Show()
End If
You may want to remove some of the title bar buttons or add code to the form Closing event to handle when the user closes via the system menu or buttons.
Using the constructor is ideal for cases where there is some bit of data which the form must have in order to do its job.
Method Two - Passing Data
Thats all well and good, but what about passing data to another form? You can use the constructor for that too. In order to pass say, a string, integer and a Point:
' destination / second form:
Public Sub New(a As String, b As Int32, c As Point)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Label1.Text = a
Label2.Text = b.ToString
Label3.Text = c.ToString
End Sub
Call it like this:
' method two: pass data you want to share in the ctor
Dim frm As New frmData("hello", 6, New Point(150, 550))
frm.Show()
Result:
Method Three: Properties
Thats fine, but if there is a lots of data that way can get cumbersome. Plus, you may want to update some of the data from the calling/main form. For this you can create Properties on the form to handle the data:
Public Property Label1Text As String
Get
Return Me.Label1.Text
End Get
Set(value As String)
Me.Label1.Text = value
End Set
End Property
Rather than a private variable to act as the backing field, one of the controls is used. The name leaves a bit to be desired as it exposes implementation details. So, use names which describe what the data represents rather than where it displays.
Public Property SpecialValue As Integer
Get
Return Integer.Parse(Me.Label2.Text)
End Get
Set(value As Integer)
Me.Label2.Text = value.ToString
End Set
End Property
Public Property SomePoint As Point
Get
Dim data = Me.Label3.Text.Split(","c)
Return New Point(Convert.ToInt32(data(0)),
Convert.ToInt32(data(1))
)
End Get
Set(value As Point)
Me.Label3.Text = value.X.ToString & "," & value.Y.ToString
End Set
End Property
A point was used just to show that other data types can be used. Setting those values from the calling/original/source form:
Using frm As New Form6
frm.Label1Text = "Ziggy"
frm.SpecialValue = 42
frm.SomePoint = New Point(111, 222)
frm.ShowDialog()
' do stuff here with any changes
Dim theint = frm.SpecialValue
End Using ' dispose of dialog
The destination controls would well have been TextBoxes for the user to edit. The Property "wrappers" allow you to fetch those values back, so in this case, a Dialog was used.
Method Four: Methods
You can also use methods as a way to pass data to the second/helper form. Here a List(of T) collection will be passed. In the child/display form a method is added to receive the data which it then displays. The task represented is proofing or viewing a filtered list:
Public Sub UpdateDisplay(lst As List(Of SimpleItem), filter As String)
DataGridView1.DataSource = lst
Label1.Text = String.Format("{0} Total {1} Items", lst.Count, filter)
End Sub
In the main/calling form:
' form level variable
Private frmDV As frmDataView
elsewhere...perhaps in a Click event:
' myList is a simple list of items
' Users pick which color to filter on via a combo box
Dim filter As String
If cboListFilter.SelectedItem IsNot Nothing Then
'Dim frmDV As New frmDataView
If frmDV Is Nothing OrElse frmDV.IsDisposed Then
frmDV = New frmDataView
End If
filter = cboListFilter.SelectedItem.ToString()
' apply the filter
Dim tmpList = myList.Where(Function(w) w.Color = filter).ToList()
frmDV.UpdateDisplay(tmpList, filter)
frmDV.Show()
Else
Return
End If
Result:
With DataBased apps a modified version of this can allow for the case where you display DataGridView data in detail form on another form. You need not have the second form rung SQL to add or update the record, and then the main form running another query to "refresh" the display. If the DataSource is a DataTable backed up by a fully configured DataAdapter, pass the DataTable and have the child form add, change or delete using that. The data will automagically be in the DataTable and DataGridView`.
There are other ways to do this, but they generally all boil down to passing something from A to B. Which way is "best" depends on what the app does, the use-case and the nature of the data. There is no one right way or best way.
For instance, Properties and in many cases Functions allow the B Form to close the feedback loop. With DB items, a DataChanged property might tell the calling form that data was added or changed so that form knows to use the DataAdapter to update the db.
'SECOND FORM
Public class secondForm (blah blah)
Public overloads property owner as myMainForm
'Must be only the form you prepared for that
Private sub secondForm_load(blah blah) handles blah blah
Texbox1.text=Owner.customcontrol.text
End sub
End class
'MAIN FORM
public class myMainForm(blah blah)
Private sub button1_click(blah blah) handles blah blah
Dim NewSecondForm as secondForm = New secondForm
NewSecondForm.owner(me)
NewSecondForm.show(me)
NewSecondForm.dispose()
' so you can have bidirectional communication between the two forms and access all the controls and properties from each other
End sub
End Class

Check to see if selection/text was changed in form

I have a form with about 20 controls on it (ComboBox, TextBox, etc) that I have pre-loaded with data. This is being displayed to the user and gives them the capability to change any of the fields.
I do not know the best way of recognizing that changes have taken place. After some research, I found TextBox.TextChanged and setting the flag IsDirty = True or something along those lines.
I don't think this will be 100% bulletproof since the user might change the value and then go back and change it to how it was when initially loaded. I've been thinking about saving the current data to .Tag and then comparing it with the .Text that was entered when the user clicks "Cancel" to simply ask them if they'd like to save the changes.
This is my code:
Private Sub Form1_Load(ByVal sender as Object, byVal e as System.EventArgs)Handles MyBase.Load
For Each ctr as Control in me.Controls
if typeof ctr is TextBox then
ctr.tag=ctr.text
end if
Next
End Sub
This is the code for when the user clicks "Cancel":
Private Sub CmdCancel_Click (ByVal sender as Object, ByVal e As System.EventArgs) Handles CmdCancel.Click
For each ctr As Control in Me.Controls
If Typeof ctr is Textbox then
if ctr.tag.tostring <> ctr.text then
MsgBox ("Do you want to save the items", YesNo)
end if
End if
Next
End sub
Is this an effective way to do this? Can it be relied on? If anyone has any better idea, I'd love to hear it.
Have a look at this:
For Each txtBox In Me.Controls.OfType(Of TextBox)()
If txtBox.Modified Then
'Show message
End If
Next
EDIT
Have a look at this. This may be of interest to you if you wanted an alternative way to the .Tag property:
'Declare a dictionary to store your original values
Private _textboxDictionary As New Dictionary(Of TextBox, String)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'You would place this bit of code after you had set the values of the textboxes
For Each txtBox In Me.Controls.OfType(Of TextBox)()
_textboxDictionary.Add(txtBox, txtBox.Text)
Next
End Sub
Then use this to find out the original value and compare to the new value:
For Each txtBox In Me.Controls.OfType(Of TextBox)()
If txtBox.Modified Then
Dim oldValue = (From kp As KeyValuePair(Of TextBox, String) In _textboxDictionary
Where kp.Key Is txtBox
Select kp.Value).First()
If oldValue.ToString() <> txtBox.Text Then
'Show message
End If
End If
Next
I know this already has an accepted answer, but I thought the part about checking if the actual text value has changed should be addressed. Checking modified will reveal if any changes were made to the text, but it will fail if the user, for example, adds a character and then deletes it. I think a good way to do this would be with a custom control, so here's an example of a simple control that stores the textbox's original text whenever it is changed programmatically, and has a textaltered property that can be checked to show whether or not the user's modifications actually resulted in the text being different from its original state. This way, each time you fill the textbox with data yourself, the value you set is saved. Then when you are ready, you just check the TextAltered property:
Public Class myTextBox
Inherits System.Windows.Forms.TextBox
Private Property OriginalText As String
Public ReadOnly Property TextAltered As Boolean
Get
If OriginalText.Equals(MyBase.Text) Then
Return False
Else
Return True
End If
End Get
End Property
Public Overrides Property Text As String
Get
Return MyBase.Text
End Get
Set(value As String)
Me.OriginalText = value
MyBase.Text = value
End Set
End Property
End Class

Checkboxlist applying If statements

I am stating VB and since it is so close to VBScript I have been having fun with it. But now I have come across the "Checkboxlist".
My boss saw me making a Windows Forms Application and asked me to make him a interface (GUI) for one of his batch files. In the batch you start by choosing between lines 1 through 10 and it does the rest. So I made a Checkboxlist and made check-boxes going from 1 to 10. Now I am not sure how to tell it that when I click a button a if statement looks at what has been checked and take to appropriate action.
I think i am suppose to start with something like
If CheckedListBox1.Items() = True then
But i know this does not work.
Anything thing will help.
Thank you.
It sounds like you're looking for the ItemCheck event. This event is fired when the checked state of an item changes.
Private Sub HandleCheckedListBox1ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
Dim item As Object = Me.CheckedListBox1.Items.Item(e.Index)
Dim text As String = Me.CheckedListBox1.GetItemText(item)
Select Case e.CurrentValue
Case CheckState.Unchecked
'...
Case CheckState.Checked
'...
Case CheckState.Indeterminate
'...
End Select
End Sub
Or iterate all checked items:
Private Sub HandleButton1Click(sender As Object, e As EventArgs) Handles Button1.Click
For Each item As Object In Me.CheckedListBox1.CheckedItems
Dim text As String = Me.CheckedListBox1.GetItemText(item)
'...
Next
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