I'm working in Visual Basic 2010 Express
I want to disable all checkbox of a Form
Not only that, as you can see in the code, there are 49 checkbox. And everyone has an event, I want to save code and optimize it.
Public Class Form1
Dim intNumber As Integer
Dim arrNumber(0 To 5) As Integer
Dim i, x, y As Integer
Dim maxCheck = 6
Dim count As Integer = 1
Private Sub setCheckbox(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox9.Click, CheckBox8.Click, CheckBox7.Click, CheckBox6.Click, CheckBox5.Click, CheckBox49.Click, CheckBox48.Click, CheckBox47.Click, CheckBox46.Click, CheckBox45.Click, CheckBox44.Click, CheckBox43.Click, CheckBox42.Click, CheckBox41.Click, CheckBox40.Click, CheckBox4.Click, CheckBox39.Click, CheckBox38.Click, CheckBox37.Click, CheckBox36.Click, CheckBox35.Click, CheckBox34.Click, CheckBox33.Click, CheckBox32.Click, CheckBox31.Click, CheckBox30.Click, CheckBox3.Click, CheckBox29.Click, CheckBox28.Click, CheckBox27.Click, CheckBox26.Click, CheckBox25.Click, CheckBox24.Click, CheckBox23.Click, CheckBox22.Click, CheckBox21.Click, CheckBox20.Click, CheckBox2.Click, CheckBox19.Click, CheckBox18.Click, CheckBox17.Click, CheckBox16.Click, CheckBox15.Click, CheckBox14.Click, CheckBox13.Click, CheckBox12.Click, CheckBox11.Click, CheckBox10.Click, CheckBox1.Click
If count < 6 Then
count = count + 1
Else
End If
End Sub
End Class
Loop through all children of the form and if the child is of type CheckBox, disable it. This should take only a few lines of code: you can use the Controls collection of the form to access children. Something like:
For Each ctrl As Control In container.Controls
If TypeOf ctrl Is CheckBox Then
ctrl.Enabled = False
End If
Next
You should do the same with event handlers: instead of having that crazy Handles control list, just add the event handler to the checkboxes in a loop during runtime. MSDN has an example on how to use AddHandler for that.
Related
I'm new to VB.NET and have been struggling all afternoon with something. I've found similar questions on the forum but none of them seemed to describe my problem exactly. I'm fairly sure that I'm missing something very basic.
I have made a main form which currently holds only one button which purpose is to open up a second form and close the main form. Based on the settings the user will select on the 2nd form the first form might have to be adapted to match with the new settings. But the problem occurs even before that.
The 'settings' form has 15 textboxes which I drew onto the form in development mode. They are called ID1, ID2,..,ID15. The values which I want to display in there are saved in an array:
Dim ids(15) as integer
Next, I created a module to simulate what you could call a control array as I used to use them in VB6.
Public sources() As TextBox = [frmSettings.ID1, frmSettings.ID2, //and so on
I did this to be able to iterate through all the 15 textboxes:
For i = 0 To 14
Sources(i).Text = ids(i + 1)
Next
Then I added on the main form this code to the Button1_Click() event:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
frmSettings.Show()
Me.Close()
End Sub
I did the same thing for the 'exit ' button on the frmSettings form.
This seems to work, but only once. I launch the application, push the button and frmSettings pops up and shows all the values from the array in the textboxes. When I push the 'close' button, I return to the main page.
So far so good, but if I try to return to frmSettings a second time, all the textboxes remain blank as if the code I added to the form never gets executed.
Any help would be greatly appreciated!
First, make sure the array that holds your data is accessible to both forms:
Module Module1
Public ids(15) As Integer
End Module
There should not be a declaration for "ids" in either form.
Next, make frmSettings itself responsible for loading and saving the data:
Public Class frmSettings
Private Sub frmSettings_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim matches() As Control
For i As Integer = 0 To 14
matches = Me.Controls.Find("ID" & (i + 1), True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is TextBox Then
Dim TB As TextBox = DirectCast(matches(0), TextBox)
TB.Text = ids(i)
End If
Next
End Sub
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
Dim valid As Boolean = True
Dim matches() As Control
For i As Integer = 0 To 14
matches = Me.Controls.Find("ID" & (i + 1), True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is TextBox Then
Dim TB As TextBox = DirectCast(matches(0), TextBox)
Dim value As Integer
If Integer.TryParse(TB.Text, value) Then
ids(i) = value
Else
MessageBox.Show(TB.Name & ": " & TB.Text, "Invalid Value", MessageBoxButtons.OK, MessageBoxIcon.Warning)
valid = False
End If
End If
Next
If valid Then
Me.Close()
End If
End Sub
End Class
I'm working on a proof of concept type situation that will eventually be tied to a scheduling database. As a Test I created this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'AddButton("test")
addLots()
End Sub
Private Sub AddLots()
Dim x As Integer
For x = 0 To 10
Dim b As New Button
Dim newLabel As New Label
newLabel.Location = New Point(100, x * 20)
newLabel.Name = x
newLabel.BorderStyle = BorderStyle.Fixed3D
newLabel.Text = newLabel.Name
Me.Controls.Add(newLabel)
Me.Controls.Add(b)
b.Location = New Point(20, x * 20)
b.Text = x
b.Tag = x
b.Name = x
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
MsgBox(B.Name)
End Sub
For this proof of concept, I simply want label 1 text to be updated when I press button 1 seems like a simple process but it's kicking my butt.
As for any object, to affect a Label you will need a reference to it. As it stands, the only reference you have is via the Controls collection of the parent control you added the Label to, i.e. the form itself. You could loop through the Controls of the form and as soon as you find a Label then you know you have the first one, or you could call OfType and First or FirstOrDefault. That assumes that there are no other Label controls on the form.
You might also consider using a dedicated parent control so that you know it will only contain the Label controls you created at run time. The obvious choice would be a TableLayoutPanel because it will handle the layout for you too.
If accessing the dynamic controls via a Controls collection is an issue then keep your own collection. Declare a member variable of type List(Of Label) and add each Label you create to it. You can then access your control from that collection and know that there are no other controls in there to get mixed up with.
By the way, if you're creating those controls at run time then they won't be automatically disposed when the form is. Make sure that you dispose them yourself and also use RemoveHandler for each AddHandler you used.
Actually, looking closer at your code, I just realised that there's a 1:1 correspondence between the Button and Label controls. It would make sense to use that. Two options are to assign the corresponding Label to the Tag of each Button or else use a Dictionary(Of Button, Label) assigned to a member variable to store the relationships. That way, you can then use the sender in the event handler, which will be the Button that was clicked, to get the corresponding Label.
Option 1.
Creating the Label:
Dim btn As New Button
Dim lbl As New Label
btn.Tag = lbl
In the event handler:
Dim btn = DirectCast(sender, Button)
Dim lbl = DirectCast(btn.Tag, Label)
Option 2.
At class level:
Private labelsByButton As New Dictionary(Of Button, Label)
Creating the Label:
Dim btn As New Button
Dim lbl As New Label
Me.labelsByButton.Add(btn, lbl)
In the event handler:
Dim btn = DirectCast(sender, Button)
Dim lbl = Me.labelsByButton(btn)
I added this to the button click event. Doesn't seem very efficient as I will eventually have 30-40 buttons and controls on the form but it works.
Private Sub Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim B As Button = sender
Dim lblToChange As Integer = B.Name
For Each objCtrl As Control In Me.Controls
If TypeOf objCtrl Is Label Then
Dim Lbl As Label = DirectCast(objCtrl, Label)
If Lbl.Name = lblToChange Then
Lbl.Text = "This ONe"
End If
End If
Next
End Sub
Hi I have a vb windows form application that has a ComboBox from the form1 I have some code that reads some registry and adds item results to combobox. I would like to select one of the results and run a start process. My problem is where do I put the code when item is selected then do something and how to I determine what has been selected?
My Code to query registry keys
Dim Key, Reader As RegistryKey, Y As String
Key = Registry.LocalMachine.OpenSubKey("SOFTWARE\AppStream\AppMgr\Shortcuts", False)
For Each X In Key.GetSubKeyNames
Reader = Registry.LocalMachine.OpenSubKey("SOFTWARE\AppStream\AppMgr\Shortcuts\" & X, False)
If Reader.GetValueNames().Contains("AppTitle") Then
Y = Reader.GetValue("AppTitle")
If Not ComboBox1.Items.Contains(Y) Then ComboBox1.Items.Add(Y)
End If
If i do somehting like this, it just shows a blank messagebox and I have not selected that text from combobox yet.
If ComboBox1.SelectedText Then
MessageBox.Show(ComboBox1.SelectedText())
End If
You subscribe to the SelectedIndexChanged event writing a method like this
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
Dim comboBox As comboBox = CType(sender, comboBox)
' Caution, the event could be called also when there is nothing selected
if combBox.SelectedItem IsNot Nothing Then
Dim curValue = CType(combBox.SelectedItem, String)
'do your stuff with the selected key'
End If
End Sub
if combBox.SelectedItem IsNot Nothing Then
Dim cmbselected As String = DirectCast(DirectCast(DirectCast(DirectCast(combBox, System.Windows.Controls.ComboBox).SelectedValue, System.Object), System.Data.DataRowView).Row, System.Data.DataRow).ItemArray(0)
End If
I want to do a For Each loop where i can check whether each button is enabled or disabled. If the button is enabled then i have to obtain the values in the tags for each button. I have 26 buttons each containing different values (cash prizes).*IMPORTANT: this code needs to go under the button so every sixth time its pressed it checks the buttons.
Pseudo-Code:
btncase1.tag = 5
Begin while statement to go through each button
Check each button to see if it is enabled
If button is enabled then obtain values
Next
Actual code i have but it doesnt make any sense to me:
Public Class Form1
Dim button As Button
Dim totalremcases As Integer
Dim btncase As New Control
Dim btncollection As New Microsoft.VisualBasic.Collection()
Private Sub btncase1_Click()
For Each button As Button In btncollection
If btncase.Enabled Then
totalremcases = totalremcases + CInt(btncase.Tag)
End If
Next
you can try to solve it by using this approach
Public Sub getallcontrolls(controls As System.Web.UI.ControlCollection)
Dim myAL As New ArrayList()
For Each ctrl As Control In controls
If TypeOf ctrl Is Button Then
If ctrl.Enabled = True Then
Dim tag As String = ctrl.Tag.ToString()
myAL.Add(tag)
End If
End If
Next
End Sub
It seem that you are making a "Deal or No Deal" kind of game.
You can create a button click counter (form level variable) so that you can keep track of how many buttons are clicked already. Increment the counter every time a button is clicked.
Create a function to accumulate values of the tags. You call this function only if the counter is divisible by 6. (You said you check every sixth time a button is pressed)
Dim counter As Integer
Dim total As Integer
Private Function AccumulateTags() As Integer
Dim ctl As Control
Dim total As Integer
For Each ctl In Me.Controls
If TypeOf ctl Is Button Then
If ctl.Enabled = True Then
total += Val(ctl.Tag)
End If
End If
Next
Return total
End Function
Private Function disable(sender As Object)
Dim ctl As Control
For Each ctl In Me.Controls
If TypeOf ctl Is Button AndAlso sender.Equals(ctl) Then
ctl.Enabled = False
End If
Next
End Function
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click, _
Button2.Click, Button3.Click, Button4.Click, Button5.Click, Button6.Click, Button7.Click
counter += 1
If counter Mod 6 = 0 Then 'Checks if counter is divisible by 6
total = AccumulateTags()
End If
MsgBox("Total" & total) 'Displays total. You may also display it in a label if you want
disable(sender)
End Sub
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