Dynamic textbox add and dispose : Few text boxes not getting disposed - vb.net

I am creating few text boxes in windows forms dynamically and at some point I dispose these
Dim tb1 As New TextBox 'new textbox
tb1.Name = "dtba" 'setname
tb1.Location = New Point(stx, sty) 'location of textbox
tb1.Text = arl(0) 'assigning text
tb1.Width = 80 'setting width
tb1.TabStop = False 'no tabstop
tb1.Enabled = False 'disabled
Me.Controls.Add(tb1) 'add to form
'Repeating same code for few more text boxes
Dim tb2 As New TextBox
tb2.Name = "dtbb"
tb2.Location = New Point(stx + 80, sty)
tb2.Text = arl(1)
tb2.Width = 175
tb2.TabStop = False
tb2.Enabled = False
Me.Controls.Add(tb2)
Dim tb3 As New TextBox
tb3.Name = "dtbc"
tb3.Location = New Point(stx + 255, sty)
tb3.Text = arl(2)
tb3.Width = 125
tb3.TabStop = False
tb3.Enabled = False
Me.Controls.Add(tb3)
Dim tb4 As New TextBox
tb4.Name = "dtbd"
tb4.Location = New Point(stx + 380, sty)
tb4.Text = arl(3)
tb4.Width = 100
tb4.TabStop = False
tb4.Enabled = False
Me.Controls.Add(tb4)
Problem occurring when I try to delete these text boxes. Code is
For Each cControl In Me.Controls
If (TypeOf cControl Is TextBox) Then
Dim txt As TextBox = CType(cControl, TextBox)
If txt.Name.Contains("dtb") Then
txt.Dispose()
End If
End If
Next cControl
Here the text boxes named dtba and dtbc getting deleted. But dtbb and dtbd are not getting deleted. Any help ?

You are editing the collection whilst looping over it. Try something like this instead:
Dim l As New List(Of Control)
For Each cControl In Me.Controls
If (TypeOf cControl Is TextBox) Then
Dim txt As TextBox = CType(cControl, TextBox)
If txt.Name.Contains("dtb") Then
l.Add(cControl)
End If
End If
Next cControl
For Each c As Control In l
c.Dispose()
Next

Instead utilize this:
For Each cControl In Me.Controls
If (TypeOf cControl Is TextBox) Then
Dim txt As TextBox = CType(cControl, TextBox)
If txt.Name.Contains("dtb") Then
txt.Dispose()
End If
End If
Next cControl
Do this:
Again:
For Each cControl In Me.Controls
If (TypeOf cControl Is TextBox) Then
Dim txt As TextBox = CType(cControl, TextBox)
If txt.Name.Contains("dtb") Then
Me.Controls.Remove(txt)
GoTo again
End If
End If
Next
The problem is related to INDEX of FOR EACH, that loss the pointer when the controls is deleted. You must repeat the operation to ensure a new index.

Related

What is the best way to loop this program?

This is one of the form, all the usercontrol value in this form will store in My.Settings
I have another form with a FlowLayoutPanel, everytime when the application start,
if Active checked then it will add a Button with discount value to the FlowLayoutPanel.
Should I add those usercontrol to a list and then loop through the list? Or what is the best way to solve this kind of problem?
UPDATED
How can I add multiple item to list in 1 code? I getting this error when system run to line 5
An exception of type 'System.NullReferenceException' occurred in XXX.exe but was not handled in user code
Additional information: Object reference not set to an instance of an object.
Public Sub RefreshDiscount(ByRef ref As scr_mainDiscount)
Dim li_disName As New List(Of TextBox)
Dim li_disValue As New List(Of TextBox)
Dim li_disType As New List(Of ComboBox)
Dim li_active As New List(Of CheckBox)
Dim tb_disName As TextBox() = {ref.tb_name1, ref.tb_name2, ref.tb_name3, ref.tb_name4, ref.tb_name5, ref.tb_name6, ref.tb_name7, ref.tb_name8, ref.tb_name9, ref.tb_name10}
Dim tb_disValue As TextBox() = {ref.tb_value1, ref.tb_value2, ref.tb_value3, ref.tb_value4, ref.tb_value5, ref.tb_value6, ref.tb_value7, ref.tb_value8, ref.tb_value9, ref.tb_value10}
Dim cb_disType As ComboBox() = {ref.cb_type1, ref.cb_type2, ref.cb_type3, ref.cb_type4, ref.cb_type5, ref.cb_type6, ref.cb_type7, ref.cb_type8, ref.cb_type9, ref.cb_type10}
Dim chkb_active As CheckBox() = {ref.CheckBox1, ref.CheckBox2, ref.CheckBox3, ref.CheckBox4, ref.CheckBox5, ref.CheckBox6, ref.CheckBox7, ref.CheckBox8, ref.CheckBox9, ref.CheckBox10}
li_disName.AddRange(tb_disName)
li_disValue.AddRange(tb_disValue)
li_disType.AddRange(cb_disType)
li_active.AddRange(chkb_active)
For index As Integer = 0 To li_active.Count - 1
If li_active(index).Checked = False Then
li_disName.RemoveAt(index)
li_disValue.RemoveAt(index)
li_disType.RemoveAt(index)
li_active.RemoveAt(index)
Else
Dim btn As New ctrl_DiscountButton
With btn
.Text = li_disName(index).Text
.Price = li_disValue(index).Text
.Type = li_disType(index).Text
End With
scr_sales.flp_discount.Controls.Add(btn)
End If
Next
li_disName.Clear()
li_disValue.Clear()
li_disType.Clear()
li_active.Clear()
End Sub
Here's a simple example showing how to find CheckBox1 thru CheckBox10, "by name", using the "searchAllChildren" option of Controls.Find():
For i As Integer = 1 To 10
Dim ctlName As String = "CheckBox" & i
Dim matches() As Control = Me.Controls.Find(ctlName, True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is CheckBox Then
Dim cb As CheckBox = DirectCast(matches(0), CheckBox)
' do something with "cb"
If cb.Checked Then
' ... code ...
' possibly use code just like this to find the matching discount value control?
End If
End If
Next

Textbox Enabled True False

This is code am trying to solve
Dim i As Integer
i = ListBox1.SelectedIndex
If ListBox1.SelectedIndex = 0 Then
TextBox10.Enabled = False
TextBox25.Enabled = False
TextBox30.Enabled = False
TextBox40.Enabled = False
TextBox55.Enabled = False
TextBox65.Enabled = False
TextBox73.Enabled = False
TextBox84.Enabled = False
TextBox95.Enabled = False
TextBox100.Enabled = False
TextBox185.Enabled = False
Else
TextBox(??).Enabled = True
End If
How to other textboxes to enable True?
I mean
10,25,30,40... 185 are false and all other textboes Enabled true ?
You can find control of type textbox and assign default enabled= true and then write your code to set enabled=false.
For Each c As Control In Me.Controls
If c.GetType Is GetType(TextBox) Then
c.Enabled=true
End If
Next
OR
Dim allTextBox As New List(Of Control)
For Each c As TextBox In FindControl(allTextBox, Me,GetType(TextBox))
c.Enabled=true
Next
Public Shared Function FindControl(ByVal list As List(Of Control), ByVal parent As Control, ByVal ctrlType As System.Type) As List(Of Control)
If parent Is Nothing Then Return list
If parent.GetType Is ctrlType Then
list.Add(parent)
End If
For Each child As Control In parent.Controls
FindControl(list, child, ctrlType)
Next
Return list
End Function
I'd go with two lists:
var falseList = new List<ListBox> { TextBox10, TextBox25, TextBox30, ... };
var trueList = new List<ListBox> { TextBox1, TextBox2, TextBox3, ... };
Then in each condition block in the if enumerate each list and set false:
foreach(var box in falseList) box.Enabled = false;
foreach(var box in trueList) box.Enabled = true;
Another option is to setup a DataSource with two booleans and set DataBinding on each of the true ListBoxes to one of the properties and the other set to the false property then setting the found property on on the datasource they all update in one statement.
Note: Sorry it's c# syntax but it's really close to VB.NET. I just don't know the exact VB syntax
You can iterate over the forms Controls collection. Something like:
Dim i As Integer
i = ListBox1.SelectedIndex
for each c in me.controls
if TypeOf c is TextBox then
dim Textbox as textbox = DirectCast(c, TextBox)
'Determine state of your textbox here.
'Perhaps use the TAG property to assign a selectedindex to each textbox
Textbox.enabled = (Textbox.Tag.ToString() <> i.ToString())
end if
next

VB.Net Loop controls by names using variables

I need to set text of some controls.
I have a Form with some CheckBoxes an some TextBoxes.
In VBA (If I have 5 TextBoxes named "TextBox1", "TextBox2", ... "TextBox5") I can use something like this:
For n = 1 To 5
Me("TextBox" & n).Text = NeededValue
Next n
I know that something like this is also possible in VB.Net but I wasn't able to find the right syntax (and I didn't find similar codes on SO).
I've tryed using
Me.Controls()
But I can't insert control name this way
Me.Controls.Find("TextBox" & n, True)
would be the similar approach to your VBA Style.
Use For Each and then test with TypeOf to find all TextBoxes in your form like :
For Each myObject1 As [Object] In Me.Controls
If TypeOf myObject1 Is TextBox Then
TryCast(myObject1, TextBox).Text = "NeededValue"
End If
Next
Also :
Dim myText = {TextBox1, TextBox2, TextBox3, TextBox4, TextBox5}
For Each btn In myText
btn.Text = "NeededValue"
Next
For i As Int32 = 1 To 5
Dim Txt = Me.Controls.Find("TextBox" & i, True)
If Txt.Length > 0 Then
Txt(0).Text = "blah"
End If
Next
Or :
For i As Int32 = 1 To 5
Dim Txt = Me.Controls.Find("TextBox" & i, True)
If Txt.Length > 0 Then
Txt(0).Text = "NeededValue"
End If
Next

Loop through Multiple Listbox Controls And Check Selected Index Of Each

I'm using the below code to try and loop through all ListBox controls in a panel on a WinForm. I want to check if any of them have a SelectedIndex above 0. If they do, I want to set a boolean value in an array to True, else set it to False:
Dim i As Integer = -1
For Each cntrl As Control In Form1.Panel3.Controls
If TypeOf cntrl Is ListBox Then
i = i + 1
If cntrl.selectedindex <> 0 Then
ReportArray(i) = True
Else
ReportArray(i) = False
End If
End If
Next
The issue I am having is that cntrl.selectedindex is not valid as .selectedindex is being picked up that it is not a member of Windows.Forms.Control
How do I get this to see it as a ListBox?
Try converting the cntrl to listbox first like this
Dim i As Integer = -1
For Each cntrl As Control In Form1.Panel3.Controls
If TypeOf cntrl Is ListBox Then
Dim TmpCntrl As ListBox = TryCast(cntrl, ListBox)
i = i + 1
If TmpCntrl.selectedindex <> 0 Then
ReportArray(i) = True
Else
ReportArray(i) = False
End If
End If
Next

How to get the object's name in vb.net

I'm trying to dynamically adding and removing objects in my form. I'm stuck on how to get the unique identifier of which object to remove.
'Collection of controls
For Each ctl In Me.Controls
'Get control type
If TypeOf ctl Is Label Then
'Get control name/index id/text or any property of current ctl
'How do I continue from here?
'Me.Controls.Remove(ctl)
End If
Next
Thanks in advance for solutions/suggestions.
If it's alright, I would like to know the explanation of the solutions.
If you guys need to know how I added objects dynamically, here it is:
For i = 1 To Spots
Dim newLabel As New Label
Dim newLoc As Integer = iLoc + (i * 30)
With newLabel
.Name = "lblSpot" & i
.Text = "Spot " & i
.Size = New Size(100, 20)
.Location = New Point(3, newLoc)
End With
AddHandler Me.Load, AddressOf frmParking_Load
Me.Controls.Add(newLabel)
Next
You can cast ctl to Label and then use .Name to find the controls to delete
Using For Each when change collection is not recommended, so here is the code you want
Dim i = 0
While i < Me.Controls.Count
Dim c = Me.Controls(i)
If TypeOf c Is Label Then
Dim Lbl As Label = CType(c, Label)
If Lbl.Name.Contains("lblSpot") Then
Me.Controls.Remove(c)
End If
End If
End While