Vb.net Set focus to nested control on another open form - vb.net

I have a form that I open from a menu item on my main form that has a datagridview that contains a control name. When I click on the control name I'd like it to set focus back to the main form and focus the control. I can get it to work if the control name is a control on the current tab, but if I try to focus to a control on another tab on my main form it does not focus. I don't get an error, it just doesn't focus.
Any assistance you could give me to point me in the right direction would be most appreciated. Thanks
My main form consists of nested controls:
Tabcontrol
Tabpage
Groupbox
Control (such as textbox, etc)
Here is my code from the 2nd form:
Public Property f1 As MainForm
Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
For Each cont As Control In f1.Controls
For Each Tp As TabPage In cont.Controls
For Each gbx As GroupBox In Tp.Controls
For Each ctrl As Control In gbx.Controls
If ctrl.Name = DataGridView1.SelectedCells(1).Value Then
ctrl.Focus()
Exit For
End If
Next ctrl
Next gbx
Next Tp
Next cont
Me.Close()
end sub

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):

Get the names of the datagridview present in the form

How can I check the number of DataGridViews on a form, and then display present their names in VB.NET?
I have tried this:
For Each dgv As DataGridView In Me.Controls
MsgBox(dgv.Name)
Next
But my guess is that Me.Controls consists of every other form controls except DataGridView?
For Each _control In Me.Controls
If TypeOf _control Is DataGridView Then
MsgBox(_control.Name)
End If
Next
I know this question is posted long time ago. In answer posted by #AadityaDengle You'll get DataGridView controls placed in form but, if DataGridView is nested in some other control (for example Panel, TableLayoutPanel, GroupBox, ...) it will not find it.
You have to search in all controls using "recursive search" way. Below is example :
'there will be stored names(id) of all DataGridView controls
Private allGrids As String = ""
Private Sub getAllGrids()
'loop through all controls on a form
For Each c As Control In Me.Controls
If TypeOf c Is DataGridView Then
'if control is DataGridView, then collect her name(id)
allGrids += c.Name.ToString + ","
Else
'if control isn't type of DataGridView and have child control(s), loop through that control
'(for example Panel, TableLayoutPanel,GroupBox, ...)
If c.HasChildren = True Then getAllGrids(c)
End If
Next
End Sub
Private Sub getAllGrids(cnt As Control)
'loop through all controls on a "container" control
'the search principle is the same like in getAllGrids on a form
For Each c As Control In cnt.Controls
If TypeOf c Is DataGridView Then
'collect DataGridView name(id)
allGrids += c.Name.ToString + ","
Else
'subroutine call hisself again with new control
If c.HasChildren = True Then getAllGrids(c)
End If
Next
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MsgBox(allGrids)
End Sub
Even though both answers by #AadityaDengle and #nelek are right I will leave my code here that I think it's a little more structured.
Note that this code does work with or without your DataGridView is placed inside a Panel or a GroupBox.
'Loop throught all DataGridViews in your Form
Private Sub FormDGV(ByVal Controlo As Control)
If Controlo.HasChildren Then
If TypeOf Controlo Is DataGridView Then
MessageBox.Show(Controlo.Name)
End If
For Each Control As Control In Controlo.Controls
FormDGV(Control)
Next
End If
End Sub´
If your DataGridViews are nested in a Panel or something like that you need to send the specifc Panel through parameter like this -
FormDGV(YourPanel)
But if they are not, you just need to send the form itselt.

Setting tab stop between two panels

I have two panels, each has several textboxes. What I want is something that seems very simple: user enter a textbox in this panel, then press Tab to jump to its 'linked' textbox in the other panel.
But, vb refuses to jump to other panel unless it finishes through all of the textboxes inside one panel, no matter what TapStop it is.
I tried to catch the tab key from a textbox, and send focus to the linked one without success: pressing Tab doesn't even fire the KeyDown nor KeyPress event.
I tried to set TabStop to the panels first, but that also fail.
So, the problem remain.. how to set tabstop.. or any similar means, to the textboxes between two panel so that when user press Tab in one panel, it will switch to the other one ?
I need the Tab key, not anyother key.
You'll have to set the TabStop property of each control on the form to False and then handle the tabbing yourself, which you can do like this:
Private Sub TextBoxes_PreviewKeyDown(sender As Object, e As PreviewKeyDownEventArgs) Handles TextBox6.PreviewKeyDown,
TextBox5.PreviewKeyDown,
TextBox4.PreviewKeyDown,
TextBox3.PreviewKeyDown,
TextBox2.PreviewKeyDown,
TextBox1.PreviewKeyDown
If e.KeyCode = Keys.Tab Then
Dim controls As Control() = {TextBox1, TextBox4, TextBox2, TextBox5, TextBox3, TextBox6, Button2}
Dim currentControlIndex = Array.IndexOf(controls, ActiveControl)
Dim nextControl = controls(currentControlIndex + 1)
nextControl.Select()
End If
End Sub
Every control you want to be able to Tab from must be in the Handles clause and every control that you want to be able to Tab to or from must be in the array and in the order you want to Tab to them in. You should also repeat the first control at the end of the array again, in order to wrap back to the beginning from the end.
Also note that no control will be selected by default if none of them a Tab stops, in which case you must manually Select the control you want to have focus by default in the form's Shown event handler.
EDIT: Here is a more complete example:
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
'Manually focus the first control after the form is displayed.
Button1.Select()
End Sub
'Include all the controls that you want to behave as Tab stops in the Handles clause.
'The order is unimportant but ordering them you will Tab to them is not a bad idea.
Private Sub TextBoxes_PreviewKeyDown(sender As Object, e As PreviewKeyDownEventArgs) Handles Button1.PreviewKeyDown,
TextBox1.PreviewKeyDown,
TextBox4.PreviewKeyDown,
TextBox2.PreviewKeyDown,
TextBox5.PreviewKeyDown,
TextBox3.PreviewKeyDown,
TextBox6.PreviewKeyDown,
Button2.PreviewKeyDown
If e.KeyCode = Keys.Tab Then
'This array must contain all controls to behave as Tab stops in order and the first must be repeated at the end.
Dim controls As Control() = {Button1, TextBox1, TextBox4, TextBox2, TextBox5, TextBox3, TextBox6, Button2, Button1}
'Find the currently active control in the array.
Dim currentControlIndex = Array.IndexOf(controls, ActiveControl)
'Get the next control in the manual tab order.
Dim nextControl = controls(currentControlIndex + 1)
'Focus that next control.
nextControl.Select()
End If
End Sub
That code works for the following form, where TextBox1, TextBox2 and TextBox3 are in Panel1 and TextBox4, TextBox5 and TextBox6 are in Panel2:

Vb.Net - Accessing text in controls on another form

I am fairly new to vb.net and would like to be able to access the value (such as .text on a textbox) from another an open form. In my application I open a form from my main form, and when I try to access the text in the controls on the main form I am unable to see the .text value on the control.
I can loop through all controls on the main form just fine, but when I want to see the actual values, all controls are empty. My controls such as text boxes and combo boxes are inside of a tab control and group boxes.
Is there a way to make all .text or values on the open form available from the other open form?
Here is how I am looping through the controls on the main form.
Try
For Each Tp As TabPage In UserData.UserTabControl.TabPages
'Name of Tabcontrol is UserTabcontrol
For Each gbx As GroupBox In Tp.Controls
For Each ctrl As Control In gbx.Controls
If ctrl.Name = "UserName" Then
MsgBox(UserData.UserName.Text) 'Messagebox here is empty
End If
Next ctrl
Next gbx
Next Tp
Me.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
Thanks in advance.
Chris
From the example you've given you already have access to a reference to your Control. Instead of going back to the Form and trying to access that control as a property of the Form you could just cast your reference and call its Text property directly.
If ctrl.Name = "UserName" Then
MsgBox(DirectCast(ctrl, TextBox).Text) 'Assuming your UserName control is a TextBox
End If
If you would like to reference controls on an open form, call it Form1:
First add a Form1 property or variable to the calling form:
Public Class Form2
Public Property f1 As Form1
...
Private Sub DoSomething()
MsgBox("Here's some text from Form1: " & f1.Textbox1.Text)
End Sub
End Class
In the callee form, set the Form2 property to the form object:
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Form2.f1 = Me
Form2.ShowDialog() ' or Form2.Show()
End Sub
End Class
You can then reference all Form1 objects from Form2 using the f1 property.
By this command, I could change the amount of control in another form.
My.Forms.myForm.labelControl.Text = "bela"
Please try this :
MsgBox(My.Forms.UserData.UserName.Text)

All Controls Click event on form

Is there a simple way to Activate the form when any controls in the form is clicked like datagirdview, panel, menustrip, button, textbox, label, etc....
it happens that my project can show many different form and it's hard for me to activate one form when it's on the back of the active form. I need to clicked the border of the form to activate it.
most likely your problem arises because your form is MDI child.. you'll have to click the menu bar to activate the form.. but if you have a borderless form, clicking on controls wont activate the form.. again, this usually happens on MDI but it shouldnt happen on a regular winform.. unless you have other running events in the background that interferes with the process.
You question is not clear at all, and I don't know what you are trying to archieve, but for executing something with a click event you have to add the handler for every control.
If you are declaring it not dinamically just:
Private Sub ControlsClick(sender As Object, e As EventArgs) _
Handles Panel1.Click, Button1.Click, TextBox2.Click ' etc.
Me.Activate 'Or Whatever
End Sub
You have to add the handler for each control. The same if you do it dinamically:
Private Sub InitializeClickHandlers(sender As Control, Optional bChilds As Boolean = True)
For Each elem As Control In sender.Controls
AddHandler elem.Click, AddressOf ControlsClick(elem, New EventArgs)
If bChilds AndAlso elem.Controls.Count > 0 Then
Call InitializeClickHandlers(sender)
End If
Next
End Sub
Then, for every control in the form, you call it like: Call InitializeClickHandlers(Me)
Or, for every control inside a panel: Call InitializeClickHandlers(Panel1)