Visual Basic - Performing an action on an object that has the focus - vb.net

I'm trying to do something very simple:
Create a method that handles multiple textbox.gotFocus() events in my form.
The goal is to select all text when the focus is given to any of the textboxes.
I know I could create an if-else block that checks to see whether or not each textbox has the focus, and then if so, just do textbox1.selectall(), or textbox2.selectall(), etc.
Is there a quicker way to do this that I'm missing that would just do it all in one statement that uses something like object.focused.selectall()? I know these aren't keywords in vb, but they're the best descriptive words I can think of to explain what I'm trying to do.
Any input is appreciated. Thanks!

What you want to do is more complicated than you think. You would have to create an event to trigger the method that handles the textboxes focus. The easy way is to put as you said a selectAll() method in every textbox gotFocus event.

Nothing built in to do that, unless you inherit from the TextBox and call SelectAll in the OnEnter override method yourself.
If you have a lot of TextBox controls, you could just iterate over the collections and add the method yourself:
Public Sub New()
InitializeComponent()
Dim ctrls As New Stack(Of Control)
ctrls.Push(Me)
While ctrls.Count > 0
Dim ctrl As Control = ctrls.Pop
If ctrl.Controls.Count > 0 Then
For Each c As Control In ctrl.Controls
ctrls.Push(c)
Next
Else
If TypeOf ctrl Is TextBox Then
AddHandler ctrl.Enter, Sub() DirectCast(ctrl, TextBox).SelectAll()
End If
End If
End While
End Sub

Since textbox doesn't have a focus event, what you can do is set up one handler to handle all the textboxes' Enter event.
Enter Event Handler
Private Sub TextboxEnter(Sender As Object, E As EventArgs)
Dim FocusedTextbox As TextBox = DirectCast(Sender, TextBox)
FocusedTextBox.SelectAll
End Sub
Add the handler for each textboxes' Enter event
For Each tb As TextBox in Me.Controls.OfType(Of TextBox)
AddHandler tb.Enter, AddressOf TextBoxEnter
Next
If you need to filter the textboxes, use a common name pattern and use a conditional to check for that pattern in the Name property.

Related

Use a virtual Keyboard on focused Textboxes and DataGridView Cells

In my Form I have various Textboxes that I write into with an in Form keyboard I created using Buttons. I have this code in Form.Load, which uses an event handler to determine which Textbox has the Focus:
For Each control As Control In Me.Controls
If control.GetType.Equals(GetType(TextBox)) Then
Dim textBox As TextBox = control
AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
End If
Next
Then I use this on each button to write a specific character:
Private Sub btnQ_Click(sender As Object, e As EventArgs) Handles btnQ.Click
If btnQ.Text = "Q" Then
FocussedTextbox.Text += "Q"
ElseIf btnQ.Text = "q" Then
FocussedTextbox.Text += "q"
End If
End Sub
Up to that point I'm good and everything works as intended. The problem is I also have a DataGridView I want to write into but can't focus on it selected cells as I do on Textboxes.
I tried this:
For Each control As Control In Me.Controls
If control.GetType.Equals(GetType(TextBox)) Then
Dim textBox As TextBox = control
AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
ElseIf control.GetType.Equals(GetType(DataGridViewCell)) Then
Dim DGVC As DataGridView = control
AddHandler DGVC.CellBeginEdit, Sub() FocussedTextbox = DGVC
End If
Next
But it just selects my last Textbox.
I declared the variable FocussedTextbox as Control so it's not specific to Textbox but any control.
Any help will be greatly appreciated.
To add text to the current ActiveControl using Buttons, these Button must not steal the focus from the ActiveControl (otherwise they become the ActiveControl).
This way, you can also avoid all those FocusedTextbox = textBox etc. and remove that code.
You just need Buttons that don't have the Selectable attribute set. You can use a Custom Control derived from Button and remove ControlStyles.Selectable in its constructor using the SetStyle method:
Public Class ButtonNoSel
Inherits Button
Public Sub New()
SetStyle(ControlStyles.Selectable, False)
End Sub
End Class
Replace your Buttons with this one (or, well, just set the Style if you're already using Custom Controls).
To replace the existing Buttons with this Custom Control:
Add a new class object to your Project, name it ButtonNoSel, copy all the code above inside the new class to replace the two lines of code you find there.
Build the Project. You can find the ButtonNoSel Control in your ToolBox now. Replace your Buttons with this one.
Or, open up the Form's Designer file and replace (CTRL+H) all System.Windows.Forms.Button() related to the Virtual KeyBoard with ButtonNoSel.
Remove the existing event handlers, these are not needed anymore.
Add the same Click event handler in the Constructor of the class that hosts those Buttons (a Form or whatever else you're using).
You can then remove all those event handlers, one for each control, that you have now; only one event handler is needed for all:
Public Sub New()
InitializeComponent()
For Each ctrl As Control In Me.Controls.OfType(Of ButtonNoSel)
AddHandler ctrl.Click, AddressOf KeyBoardButtons_Click
Next
End Sub
Of course, you also don't need to add event handlers to any other control, this is all that's required.
Now, you can filter the Control types you want your keyboard to work on, e.g., TextBoxBase Controls (TextBox and RichTextBox), DataGridView, NumericUpDown etc.
Or filter only special cases that need special treatment (e.g., MonthCalendar).
To add the char corresponding to the Button pressed, you can use SendKeys.Send(): it will insert the new char in the current insertion point, so you don't need any other code to store and reset the caret/cursor position as it happens if you set the Text property of a Control.
In this example, I'm checking whether the ActiveControl is a TextBoxBase Control, then just send the char that the clicked Button holds.
If it's a DataGridView, first send F2 to enter Edit Mode, then send the char.
You could also just send a char (so, no filter would be required), but in this case, you'll replace, not add to, the existing value of that Cell.
Private Sub KeyBoardButtons_Click(sender As Object, e As EventArgs)
Dim selectedButton = DirectCast(sender, Control)
Dim keysToSend = String.Empty
If TypeOf ActiveControl Is TextBoxBase Then
keysToSend = selectedButton.Text
ElseIf TypeOf ActiveControl Is DataGridView Then
Dim ctrl = DirectCast(ActiveControl, DataGridView)
If TypeOf ctrl.CurrentCell IsNot DataGridViewTextBoxCell Then Return
SendKeys.Send("{F2}")
keysToSend = selectedButton.Text
Else
' Whatever else
End If
If Not String.IsNullOrEmpty(keysToSend) Then
SendKeys.Send(keysToSend)
End If
End Sub
► Note that {F2} is sent just once: when the Cell enters Edit Mode, the ActiveControl is a DataGridViewTextBoxEditingControl, hence a TextBox Control, handled by the TextBoxBase filter.
This is how it works (using just the code posted here):

How to add a specific event handler to a unspecified control?

I'm looking to try and create something like the following:
If the user leaves the last textbox (for example let's say TextBox8), then a new textbox is created below textbox8 with the name textbox9. I have this part, but how would I make it so that if textbox9 is left, the same events happen, so on and so forth?
Private Sub TextBox8_LoseFocus(sender As Object, e As System.EventArgs) Handles TextBox8.LostFocus
' Textbox 9 creation code which then creates the next textbox etc.
End Sub
If anybody can offer a better way of doing this sort of thing
You can use AddHandler to add a eventhandler to a control you create at run time
AddHandler TextBox9.LostFocus, AddressOf TextBox8_LoseFocus

Change a checkbox text and function based on checkbox.checkstate in groupbox

I'm trying to teach myself VB .net and as my first project I'm trying to design a form that functions much like the checkboxes in Gmail. Tons of checkboxes in a group and one checkbox that sits outside the group to select/deselect those within.
I've gotten far enough to have that master checkbox do its thing, but I would really like to have the form notice whenever anything within the groupbox is checked by the user, then to change its text & function automatically. The code I came up with to change the text works, but I can't figure out where to put it:
For Each ctrl As CheckBox In GroupBox1.Controls
If ctrl.CheckState = 1 Then
CheckBox1.Text = "Deselect All"
End If
Next
I can link the code to a button push or a checkbox change, but I'd like it to be automatic since having the user click something to run the check defeats the purpose. I tried double clicking the groupbox and placing the code there but it does nothing. Also tried double clicking the form background but it does nothing there either. Please help.
As you have probably noticed, there may be a few different places where you need to do this. To reuse a piece of functionality, create a new method that does that job. Double-click the form, and place this just before the End Class:
''' <summary>Update each of the CheckBoxes that in the same GroupBox</summary>
''' <param name="sender">The CheckBox that was clicked.</param>
''' <param name="e"></param>
''' <remarks>It is assumed that only checkboxed that live in a GroupBox will use this method.</remarks>
Public Sub UpdateCheckBoxState(ByVal sender As System.Object, ByVal e As System.EventArgs)
'Get the group box that the clicked checkbox lives in
Dim parentGroupBox As System.Windows.Forms.GroupBox = DirectCast(DirectCast(sender, System.Windows.Forms.CheckBox).Parent, System.Windows.Forms.GroupBox)
For Each ctrl As System.Windows.Forms.Control In parentGroupBox.Controls
'Only process the checkboxes (in case there's other stuff in the GroupBox as well)
If TypeOf ctrl Is System.Windows.Forms.CheckBox Then
'This control is a checkbox. Let's remember that to make it easier.
Dim chkBox As System.Windows.Forms.CheckBox = DirectCast(ctrl, System.Windows.Forms.CheckBox)
If chkBox.CheckState = 1 Then
chkBox.Text = "Deselect All"
Else
chkBox.Text = "Select All"
End If
End If ' - is CheckBox
Next ctrl
End Sub
Now you have a method that will do what you want, you need to connect it to each CheckBox that you want to manage. Do this by adding the following code in The Form_Load event:
AddHandler CheckBox1.CheckedChanged, AddressOf UpdateCheckBoxState
AddHandler CheckBox2.CheckedChanged, AddressOf UpdateCheckBoxState
...
So now the same method will handle the ClickChanged method of all of your connected checkboxes.
You can also update the checkBoxes in addition to when the user clicks it by calling the Method UpdateCheckBoxState(CheckBoxThatYouWantToProgramaticallyUpdate, Nothing) perhaps in Form_Load, or elsewhere.

Check which checkbox is checked with loop

What would be the syntax to check inside a visual basic form panel for checkboxes and find which are checked? I understand how I Could use a for loop and an if statement, but I'm confused as to the syntax to check for each checkbox. for example:
Dim i As Integer
For i = 1 To 10
'Here is where my code would go.
'I could have ten checkboxes named in sequence (cb1, cb2, etc),
'but how could I put i inside the name to test each checkbox?
Next
You need to loop through the Controls collection of the control that has the Checkbox's added to it. Each Control object has a Controls collection. I would prefer a For Each loop in this scenario so I get the Control right away without having to get it using the Controls index If your CheckBoxes are added to the Panel directly, the easiest way to do it would be..
For Each ctrl As var In panel.Controls
If TypeOf ctrl Is CheckBox AndAlso DirectCast(ctrl, CheckBox).IsChecked Then
'Do Something
End If
Next
I'm not very familiar with the VB.Net syntax, but in psudo-code:
ForEach CheckBox in ControlContainer
DoSomething
Next
If you have all of your CheckBox controls in a single container - e.g. a Panel - then the above code would iterate each control that is a CheckBox.
Try this :
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If CheckBoxList1.Text = "" Then
do/display something
Exit Sub
Else
For Each item As ListItem In CheckBoxList1.Items
If item.Selected Then
do/display something
End If
Next
End If
End Sub

Rookie With Events; Causing Action after hitting F5

So yes I'm very new to creating my own custom events. I can do the basics when I put controls on a form but this one is a little more complex. I have an application that reads in a .TSV and populates a form with controls based on the number of objects it "reads." So for instance: I have a file that contains 10 people objects and my code populates a form with controls for each person. Easy stuff!
Now lets say I have a ComboBox with the items: "Alive", "Deceased", "Unborn". Right next to this I have a textbox for age. Now originally, this textbox is not enabled because the default value for the ComboBox is "Unborn". But lets say when the user selects "Alive", I want that textbox to become enabled so an age can be entered.
Obviously from me asking this and the title of this question, I don't know how to go about doing this. I don't really understand events and I learn by example but the MSDN examples don't quite cut it.
Any help (especially an awesome Step-by-Step guide) would be greatly appreciated.
From what I gather from the comments, you want to add events to a form object that is created at runtime. Use the AddHandler command to the object. Something to the effect of:
AddHandler NameOfFormObject.TypeOfAction, AddressOf HowToHandle
Private Sub HowToHandle(ByVal sender as System.Object, ByVal e As System.EventArgs)
DropDownMenu.enabled = True
End Sub
Doing it this way, you will be able to modify the events of an object created at runtime. In your case, it sounds like you'll want to use the action that Josaph recommended, and end up incorporating both solutions offered, like so
AddHandler ComboBox1.SelectedIndexChanged, AddressOf HowToHandle
Private Sub HowToHandle(ByVal sender as System.Object, ByVal e As System.EventArgs)
If DirectCast(sender, ComboBox).SelectedIndex = 0 'Alive
DirectCast(DirectCast(sender, ComboBox).Tag, TextBox).enabled = True
Else
DirectCast(DirectCast(sender, ComboBox).Tag, TextBox).enabled = False
End If
End Sub
You will want to use the ComboBox_SelectedIndexChanged() event to capture that the combo box item has been changed. At that point, you will need to check to see which combo box item has been selected and make a decision as to whether the TextBox should be enabled or not. Here is an example. Note: This example assumes that "Alive" is the first item in your combobox at the 0 index.
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
If ComboBox1.SelectedIndex = 0 Then 'Alive
TextBox1.Enabled = True
Else
TextBox1.Enabled = False
End If
End Sub
Dynamically generate the combobox and add handler.
Dim cmb as New ComboBox
AddHandler cmb.SelectedIndexChanged, AddressOf ComboBox1_SelectedIndexChanged
Me.Controls.Add(cmb)
I suppose that as you will have 10 comboboxes... in the same way you'll have 10 textboxes.
In that case... once you attach and handle the event as AndyPerfect and Joseph... in that method you will need code something to know which of the Textboxs you need to enable/disable.
First you need to know which combobox triggered the event: this is done using the "sender" parameter. ctype(sender, Combobox) to access the methods and properties of the ComboBox.
Once you know which combo, you need to activate/deactivate the correct textbox.
To accomplish this, you'll need to add a reference to the TextBox in the "TAG" property of the Combobox at the moment of creating it.
Dim txt as new TextBox
Dim cmb as new ComboBox
cmb.Tag = txt
Then... you simple use:
ctype(ctype(sender, Combobox).Tag, TextBox).Enable = true
Here is how I ended up writing it in the end. I appreciate all the help! Thank you!
If DirectCast(sender, ComboBox).SelectedIndex = 2 Then
DirectCast(Me.Controls.Item(DirectCast(sender, ComboBox).Tag), TextBox).Enabled = True
Else
DirectCast(Me.Controls.Item(DirectCast(sender, ComboBox).Tag), TextBox).Enabled = False
End If