If any checkbox is checked then certain textboxes will be enabled - vb.net

In private sub form1_loader:
For each obj as object in Me.Controls
If TypeOf obj is windows.forms.textbox then
Directcast(obj, windows.forms.textbox).enabled = false
End if
Next
But I also wanted to have some certain textboxes to be enabled if any checkbox has been checked (even if there's only one checked)
And disable if none of the checkboxes are checked.
I am not familiar in coding and it's my first time for class activity so I don't know a lot.
Would there be a way for this one or should I manually code for every private sub of checkboxes?

This will enable three specific TextBoxes if and only if at least one of three specific CheckBoxes are checked:
Dim anyCheckBoxChecked = {CheckBox1, CheckBox2, CheckBox3}.Any(Function(cb) cb.Checked)
For Each tb In {TextBox1, TextBox2, TextBox3}
tb.Enabled = anyCheckBoxChecked
Next
You can extend that to any set of either type of control, e.g. all controls of that type in a specific container:
Dim anyCheckBoxChecked = Panel1.Controls.OfType(Of CheckBox)().Any(Function(cb) cb.Checked)
For Each tb In Panel2.Controls.OfType(Of TextBox3)()
tb.Enabled = anyCheckBoxChecked
Next

Related

using a collection of comboboxes to change the Enabled Property

I am building a large data entry form and want to enable or disable groups of comboboxes based on a checkbox ( if the check box gets checked, the collection of combo boxes get enabled for user input and vice versa ). I want to use collection, because the comboboxes are not always going to be in sequential order ( example : Comboboxes 1-7, then Combobox 12, then 16, and 45-57 ). A collection seems ideal.
I've built the collections, added the comboboxes, and added items to the comboboxes. All the items are there in the comboboxes when I run the Application. I can enable or disable them individually, but I can't enable/disable the comboboxes as a collection.. how can I enable or disable them as a group ?
I can get this to work if I select all the combo boxes in my form, and then run the thru list matching the names against a variable ( as an example, for boxes 1 - 56 ), but that makes using a collection redundant. I am also going to want to output the data, in the collection groups, for later use.
I've been beating my head against the wall for a day or so on this..
Declare Collection
Dim CablesCollectionBoxes As New Collection
Add Comboboxes to collection
CablesCollectionBoxes.Add(ComboBox1)
CablesCollectionBoxes.Add(ComboBox2)
CablesCollectionBoxes.Add(ComboBox3)
.
<removed for space and readability>
.
CablesCollectionBoxes.Add(ComboBox56)
I am trying modify the collection of ComboBoxes to a disabled state, but the code below won't work.
for I as integer = 1 to 56
CablesCollectionBoxes.Item(i) = Disabled
next
It DOES work if I use this, but I'm not using the collection, I am running thru ALL the comboboxes and matching names :
For i As Integer = 1 To 56
Dim clsCombo As ComboBox = DirectCast(Me.Controls.Find("ComboBox" & i.ToString(), True)(0), ComboBox)
clsCombo.Enabled = True
Next
or this
ComboBox1.Enabled = True
ComboBox2.Enabled = True
ComboBox3.Enabled = True
ComboBox4.Enabled = True
.
<removed for space and readability>
.
ComboBox56.Enabled = True
How do I access the comboboxes as a group, and change the properties ? Did I declare the collection incorrectly ?
Don't use collection. Collections are soft-deprecated. Use List(Of T)
Dim comboList As New List(Of ComboBox)()
comboList.Add(cbo1)
comboList.Add(cbo2)
comboList.Add(cbo3)
' Imports System.Linq
comboList.ForEach(Sub(cbo) cbo.Enabled = True)
This is as close as you can get.
Now, if you want to have some selective way to enable/disable or whatever, you can use Tag property to mark and then it will look like this
comboList.Where(Function(cbo) cbo.Tag IsNot Nothing AndAlso CBool(cbo.Tag)).ToList().ForEach(Sub(cbo) cbo.Enabled = True)
Be sure that the check box and the enabled property of the combos are in syn when the program starts. Use the designer.
Private ComboCollection As New List(Of ComboBox)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BuildCBCollection()
End Sub
Private Sub BuildCBCollection()
For Each ctrl As Control In Me.Controls
If TypeOf (ctrl) Is ComboBox Then
ComboCollection.Add(CType(ctrl, ComboBox))
End If
Next
End Sub
Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
For Each cb In ComboCollection
cb.Enabled = Not cb.Enabled
Next
End Sub

How to reference a variable control on a variable form from another form? Need to get the button.Tag renamed in running program

Here's my problem:
I have a form with a treeview.
That treeview shows all:
other forms in my project as parents
all buttonnames as childs
all buttontags as childs of the buttonnames.
When i select a buttonname in the treeview i have the selection presented as
(textbox1 with the buttonname)
(textbox2 with the buttontag)
(textbox3 with the formname)
I have 1 empty textbox which i want to fill manually, to update the buttontag from the button selected in the treeview.
Either way, all code I have tried ain't updating anything.
This is the code so far, but doesn't seem to work...
My Code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim asm = System.Reflection.Assembly.GetExecutingAssembly
Dim myTypes As Type() = asm.GetTypes()
Dim frm As Form
For Each t As Type In myTypes
If t.IsSubclassOf(GetType(System.Windows.Forms.Form)) AndAlso TextBox1.Text = t.Name Then
frm = CType(Activator.CreateInstance(t), Form)
frm.Hide()
Dim thisButtonName As String = TextBox3.Text ' This is the name of the button I'm looking for
Dim thisButtonName2 As String = TextBox2.Text ' this is the new tag name for that button
' Loop all controls in this form
For Each ctrl As Control In Controls
' Is this control a button
If TypeOf (ctrl) Is Button Then
' Is this the correct button
If CType(ctrl, Button).Name = thisButtonName Then
CType(ctrl, Button).Tag = thisButtonName2
End If
End If
Next
End If
Next
TreeView1.Nodes.Clear()
For Each formprop In My.Forms.GetType.GetProperties
Dim node = Me.TreeView1.Nodes.Add(formprop.Name)
Dim form As Form = CType(formprop.GetValue(My.Forms, Nothing), Form)
ControlsTree(node, form.Controls)
Next
End Sub
I think there are two basic problems here:
Your loop For Each ctrl As Control In Controls is not iterating over the controls in the other form object referenced by the frm variable. The Controls property is going to default to this form's set of Controls, not frm.Controls.
It seems like you are trying to change the Tag in the definition of that class at run-time. That is not possible, AFAIK, especially in what you're trying here. Each time you create a new instance of that form object, you are going to get that object initialized as how it was compiled. You can change the Tag values of a running instance of the object, but you can't change the default values of the class without using a technique like dependency injection.

Making a List(Of ...) from multiple form object

So I'm trying to make a list of more than one type of object, which I done a research on and found out it's, but I also researched into structures and found I can possibly make a use of that instead, but it doesn't return itself as a list.
Imports WinText = System.Windows.Forms.TextBox
Imports WinCombo = System.Windows.Forms.ComboBox
Public Class PSS
Public EntryItems = New List(Of Elements)
Structure Elements
Dim xSchool As WinCombo
Dim xClass As WinCombo
Dim xID As WinCombo
Dim xName As WinText
End Structure
End Class
Edit: So on a form I have a set of ComboBoxes and TextBoxes (about 20 more than on the example here). I want to put them into a list so that when I will be retrieving their results, or getting their names for SQL references, or anything similar, I will be able put them into a loop, thus making the code more efficient and shorter to do.
Structure has similarities to Class and is not a list.
(Read more about here)
You can create a List(Of Structure) but you need to populate it first, like djv stated already in comments.
Private Sub Populate()
Dim list As New List(Of Elements)
list.Add(New Elements)
'Add as much Elements as you want
End Sub
Assuming your Controls are placed on a Form named Form1.
For Each ctrl As Control In Form1.Controls
If TypeOf ctrl Is TextBox Then
Dim tb As TextBox = DirectCast(ctrl, TextBox)
'Do whatever you want with the current TextBox
ElseIf TypeOf ctrl Is ComboBox Then
Dim chk As ComboBox = DirectCast(ctrl, ComboBox)
'Do whatever you want with the current ComboBox
End If
Next
At first, credits to MatSnow.
Taking his concept of As Control I was able to make a List(Of Control) which allowed me to make and add items to it.
Dim ControlList As New List(Of Control)
ControlList.Add(ComboBox1)
ControlList.Add(TextBox1)
'And so on

Looping through all Combo boxes on a VB form

I am making a grade application for a school project and I am wondering how I can loop through and check a value in all combo boxes on a certain form, I have 19 units to check; trying to be efficient without making 19 case statements. I have tried an array and me.controls.
Try this :
For Each c As Control In Me.Controls.OfType(Of ComboBox)()
'You cann acces to ComboBox her by c
Next
Note that if you have controls host by containers (TabControl, SPlitPanel, etc.) you may not find all of your controls.
Here is a recursive call that should return all of your controls:
Sub GetControlList(container As Control, ByVal ctlList As List(Of Control))
For Each child As Control In container.Controls
ctlList.Add(child)
If (child.HasChildren) Then
GetControlList(child, ctlList)
End If
Next
End Sub
I have on occasion had problems with the controls on SplitContainer panels so if you use a splitter make sure you are getting all your controls.
Once you have a complete list of controls you can operate on them. This sample is working with DataGridView controls:
Dim ctrls As New List(Of Control)
GetControlList(Me, ctrls)
For Each dgv As DataGridView In ctrls.OfType(Of DataGridView)()
AddHandler dgv.DataError, AddressOf DataGridView_DataError
Debug.Print(dgv.Name)
Next
FYI the generic data error code:
Private Sub DataGridView_DataError(sender As Object, e As DataGridViewDataErrorEventArgs)
Dim dgv As DataGridView = sender
Dim sGridName As String = dgv.Name.Replace("DataGridView", "")
Dim col As DataGridViewColumn = dgv.Columns(e.ColumnIndex)
Dim sColName As String = col.HeaderText
MsgBox(sGridName & vbNewLine & "Column " & sColName & vbNewLine & e.Exception.Message, MsgBoxStyle.Exclamation)
End Sub
You already have the OfType(OF T) method. You use it like this:
ForEach box As ComboBox In MyForm.Controls.OfType(Of ComboBox)()
Next
But this only checks the direct children of your control. If you have container controls like GroupBox, Panels, FlowControlLayoutPanel, etc, you'll miss the controls nested inside them. But we can build a new OfType() method to search these recursively:
Public Module ControlExtensions
<Extension()>
Public Iterator Function OfTypeRecursive(Of T As Control)(ByVal Controls As ControlCollection) As IEnumerable(Of T)
For Each parent As Control In Controls
If parent.HasChildren Then
For Each child As Control In OfTypeRecursive(Of T)(parent.Controls)
Yield child
Next child
End If
Next parent
For Each item As Control In Controls.OfType(Of T)()
Yield item
Next item
End Function
End Module
And you use it the same way:
ForEach box As ComboBox In MyForm.Controls.OfTypeRecursive(Of ComboBox)()
Next
You'll probably want to check containers for controls of the type you're looking for, here's a little function that should do the trick for you.
Private Function GetControls(Of T)(container As Control, searchChildren As Boolean) As T()
Dim Controls As New List(Of T)
For Each Child As Control In container.Controls
If TypeOf Child Is T Then
DirectCast(Controls, IList).Add(Child)
End If
If searchChildren AndAlso Child.HasChildren Then
Controls.AddRange(GetControls(Of T)(Child, True))
End If
Next
Return Controls.ToArray()
End Function
Here's the usage, if search children is True then all child containers will be searched for the control you're looking for. Also, for the top most container we'll just pass in Me assuming you're calling the code from within your Form, otherwise you could pass the Form instance or a specific Panel, GroupBox, etc.
Dim ComboBoxes As ComboBox() = GetControls(Of ComboBox)(Me, True)

Loop controls in form and tabpages

I have form with tabcontrol and few tab pages which contain many settings in textboxes and checkboxes.
When user press Exit from this form I have to check if data was changed.
For that I thought to make a string on Enter of all values on form and compare it with string of all values on exit:
Private Function getsetupstring() As String
Dim setupstring As String = ""
For Each oControl As Control In Me.Controls
If TypeOf oControl Is CheckBox Then
Dim chk As CheckBox = CType(oControl, CheckBox)
setupstring &= chk.Checked.ToString
End If
If TypeOf oControl Is TextBox Then
setupstring &= oControl.Text.Trim.ToString
End If
Next
Return setupstring
End Function
But that code don't loop through controls which are on tab pages, only TabControl and few buttons which are on top of form.
What to do to get all controls listed so I can pick values?
Controls only contains the parent controls, not the respective children. If you want to get all the controls (parents and respective children), you can rely on a code on these lines:
Dim allControls As List(Of Control) = New List(Of Control)
For Each ctr As Control In Me.Controls
allControls = getAllControls(ctr, allControls)
Next
Where getAllControls is defined by:
Private Function getAllControls(mainControl As Control, allControls As List(Of Control)) As List(Of Control)
If (Not allControls.Contains(mainControl)) Then allControls.Add(mainControl)
If mainControl.HasChildren Then
For Each child In mainControl.Controls
If (Not allControls.Contains(DirectCast(child, Control))) Then allControls.Add(DirectCast(child, Control))
If DirectCast(child, Control).HasChildren Then getAllControls(DirectCast(child, Control), allControls)
Next
End If
Return allControls
End Function
Other alternative you have is relying on the Controls.Find method with the searchAllChildren property set to True.