vb.net Keydown event on whole form - vb.net

I have a form with several controls. I want to run a specific sub on keydown event regardless any controls event.
I mean if user press Ctrl+S anywhere on form it execute a subroutine.

You should set the KeyPreview property on the form to True and handle the keydown event there
When this property is set to true, the form will receive all KeyPress,
KeyDown, and KeyUp events. After the form's event handlers have
completed processing the keystroke, the keystroke is then assigned to
the control with focus. .......... To handle keyboard
events only at the form level and not allow controls to receive
keyboard events, set the KeyPressEventArgs.Handled property in your
form's KeyPress event handler to true.
So, for example, to handle the Control+S key combination you could write this event handler for the form KeyDown event.
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles MyBase.KeyDown
If e.Control AndAlso e.KeyCode = Keys.S then
' Call your sub method here .....
YourSubToCall()
' then prevent the key to reach the current control
e.Handled = False
End If
End Sub

I've used this code in my forms before and it seems to work pretty good.
Protected Overrides Function ProcessKeyPreview(ByRef m As System.Windows.Forms.Message) As Boolean
If m.Msg = &H100 Then 'WM_KEYDOWN
Dim key As Keys = m.WParam
If key = Keys.S And My.Computer.Keyboard.CtrlKeyDown Then
'DO stuff
Return True
End If
End If
Return MyBase.ProcessKeyPreview(m)
End Function

Related

Winforms Placeholder Text is Overwritten

I am attempting to give a winforms Textbox control placeholder text by programmatically setting the respective control's text during the GetFocus and LostFocus events. However, for whatever reason the control never reflects the updated text.
This is what I'm attempting:
Private Sub TextBoxEmail_GotFocus(ByVal sender As Object, ByVal e As EventArgs) Handles TextBoxEmail.GotFocus
Dim this As TextBox = DirectCast(sender, TextBox)
With this
If .Text = "Email Address" Then
.ForeColor = Bootstrap.Utilities.Color.TextBody
.Text = String.Empty
End If
End With
End Sub
Private Sub TextBoxEmail_LostFocus(ByVal sender As Object, ByVal e As EventArgs) Handles TextBoxEmail.LostFocus
Dim this As TextBox = DirectCast(sender, TextBox)
With this
.ForeColor = Bootstrap.Utilities.Color.TextLight
If String.IsNullOrWhiteSpace(.Text) Then
.Text = "Email Address"
End If
End With
End Sub
What is odd is that if I setup a breakpoint in the LostFocus event handler and step through the code using the F11 shortcut, it is constantly cycles through the GotFocus and LostFocus events.
It happens because you are debugging the code.
When your text box gets focus at that time GetFocus event will call unfortunately you have put a breakpoint in GetFocus as well as LostFocus event. so your form Lose the focus and that focus comes to the visual studio so LostFocus event will occur after that again after the debuging process is complete your text box get focused again so again GetFocus event will call and its process will create Cycle while you debug the code.
I hope this will help you.

DataGridView.RowLeave fires before a Form button.MouseClick

I can't find anything about this anywhere:
I have a form with a DataGridView and a few Buttons. When a row of the datagridview is selected, and I click a button (on the form), dgv.RowLeave triggers before anything else. It triggers even before Click or MouseClick.
That kind of makes sense, but the problem is that the sender of RowLeave(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) is the DataGridView, not the button. So it doesn't seem to be possible to know at that point what button was clicked on, because sender and e both refer to the DataGridView, not the Form nor the Buttons.
The Click event is triggered, but only after RowLeave was processed.
So is there any way to know where the user clicked, before RowLeave does other things (in my case, resulting in the Button.Click to be never handled), or then from within RowLeave?
Class MainForm
' The form contains a DataGridView and btnQuit (and other buttons)
Private Sub dgv_RowLeave(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgv.RowLeave
ProgrammaticallyDoRowValidation(dgv.CurrentRow.Index) ' This does validation and more.
' But if btnQuit is clicked, I need to know here, or before RowLeave is
' triggered and NOT do this row validation.
' ...
End Sub
Private Sub Form_Click(sender As Object, e As EventArgs) Handles MyBase.Click
Dim frm As Form
frm = CType(sender, Form)
' Translated from Sach's comment below. Code never reaches this event
'(RowLeave prevents it).
End Sub
Private Sub Quit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnQuit.MouseClick
QuitPgm() ' Contains some more stuff.
' Also never executed, because RowLeave is handled first.
End Sub
End Class
I'm using WinForms here, but the idea is the same.
So Events are attached to Controls. A Button is a Control, so is a DataGridView. Then in the Code Behind you have Event Handlers which are essentially methods tied to Control Events.
So when you attach a Click event to a button, behind-the-scenes, VB.NET creates an Event Handler like so:
private void button1_Click(object sender, EventArgs e)
{
}
Now the sender is an object, but it's actually the DataGrid that is passed there. So contrary to your statement So it doesn't seem to be possible to know at that point what button was clicked on you CAN know if a button was clicked on. If it was, and if you have an event handler attached, it will get called. For example, this will show a MessageBox with the button text:
private void button1_Click(object sender, EventArgs e)
{
var btn = (Button)sender;
MessageBox.Show(btn.Text);
}
So if you want to know if the Form was clicked, attach a Click event handler:
private void Form1_Click(object sender, EventArgs e)
{
var frm = (Form)sender;
MessageBox.Show(frm.Text);
}
I'm not sure how you prevent the button click in your RowLeave event, but I think you should use RowValidating event to validate the DataGridView. Let's say we have a DataGridView with only 1 column and a Button. The validation is the column value must not higher than 100. If we put the validation in the RowValidating event, the validation is triggered after the Leave event but before Validated event. If the validation fails, the subsequence events are not fired.
Public Class Form1
Function ProgrammaticallyDoRowValidation(i As Integer) As Boolean
If Convert.ToInt32(dgv(0, i).Value) > 100 Then
Return False
Else
Return True
End If
End Function
Private Sub dgv_RowValidating(sender As Object, e As DataGridViewCellCancelEventArgs) Handles dgv.RowValidating
If Not ProgrammaticallyDoRowValidation(dgv.CurrentRow.Index) Then
e.Cancel = True
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MessageBox.Show("Buton clicked")
End Sub
End Class
Try running the code and enter a value higher than 100 in the column. You can't click the button because it fails the validation. But if you set the Button's CausesValidation property to False, the validation won't be triggered.
The order of event according to this link is like this:
When you change the focus by using the keyboard (TAB, SHIFT+TAB, and
so on), by calling the Select or SelectNextControl methods, or by
setting the ContainerControl.ActiveControl property to the current
form, focus events occur in the following order: Enter -> GotFocus ->
Leave -> Validating -> Validated -> LostFocus
When you change the focus by using the mouse or by calling the Focus
method, focus events occur in the following order: Enter -> GotFocus
-> LostFocus -> Leave -> Validating -> Validated
So is there any way to know where the user clicked, before RowLeave
does other things (in my case, resulting in the Button.Click to be
never handled), or then from within RowLeave?
Private Sub dgv_RowLeave(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgv.RowLeave
ProgrammaticallyDoRowValidation(dgv.CurrentRow.Index) ' This does validation and more.
' But if btnQuit is clicked, I need to know here, or before RowLeave is
' triggered and NOT do this row validation.
' ...
End Sub
This is a bit of a kludge solution, but within the DataGridView.RowLeave event, you can check if the ContainerControl.ActiveControl Property to see if the currently active control is the one you want to test for. In this case the ContainerControl is the Form.
Private Sub dgv_RowLeave(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgv.RowLeave
ProgrammaticallyDoRowValidation(dgv.CurrentRow.Index) ' This does validation and more.
' But if btnQuit is clicked, I need to know here, or before RowLeave is
' triggered and NOT do this row validation.
' ...
If Me.ActiveControl Is btnQuit Then
' do something
End If
End Sub

How do I override a keypress event in a Custom Base Winforms in vb.net

I have downloaded a dll for a custom base Winforms as my base form, the developer of the custom form is no longer available and all of my forms inherits on this base form as it has some functionalities common to all of my other forms, my problem here is that the event when I press the ESC key exits or closes the active form immediately without a warning, I wanted to override the keydown event of the ESC key but it does not work. I tried this code below but they are not working, When I press ESC the form closes since the ESC Event which closes the form is embedded in the custom base form.
Private Sub frmMain_KeyPress(sender As Object, e As KeyPressEventArgs)
If e.KeyChar = Chr(27) Then
e.Handled = True
End If
End Sub
Private Sub frmMain_KeyDown(sender As Object, e As KeyEventArgs)
If e.KeyCode = Keys.Escape Then
e.Handled = True
End If
End Sub
try to use overrides event,
Overriding Event Handlers with Visual Basic .NET
It seems that your base form has the property KeyPreview set to True. You need to set it to false, probably the best place will be at the end of your constructor.
'frmMain.vb
Public Sub New()
InitializeComponent()
MyBase.KeyPreview = False
End Sub
More information on KeyPreview property here

KeyDown Event Key Not Work - VB.net

KeyDown event does not work, pressing escape the form does not close
Private Sub DataTable_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
If e.KeyCode = Keys.Escape Then
Me.Close()
End If
End Sub
Well, sure it works, the event is just not very like to fire. Keystrokes raise the KeyDown event on the control with the focus. That will only ever be your form when it has no controls that can get the focus. A fairly unlikely scenario.
If you already have a Button labeled "Cancel" that closes the form then set the form's CancelButton property.
If you don't have such a button then it gets to be pretty unlikely that the user will figure out by himself that the Escape key is useful. He will most likely use the Close button in the upper right corner. You can nevertheless make it work by overriding the ProcessCmdKey() method. Like this:
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
If keyData = Keys.Escape Then
Me.Close()
Return True
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function

Change action in Control + F4 Vb.net

My application is parent, child application. Child forms shows then press cntrl + F4 the child form is closed. How to block the action and the same time if i press cntrl + F4 the child form have submit button that event is invoked.
How can i do that?
I am using below coding is block the control + F4
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, ByVal keyData As Keys) As Boolean
If keyData = Keys.Control Or Keys.F4 Then Return True
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
This event already exists, the FormClosing event fires. You can cancel the close by setting e.Cancel = True in your event handler for the event. Be sure to check the e.CloseReason before you do that.
Do avoid breaking standard Windows shortcut keystrokes, there is no point. The user can also close the window by clicking the child window's Close button. Ctrl+F4 is just a helpful shortcut to do the same thing without using the mouse.
You have to catch the form closing event, then test if it's done by key-press.
I assume you mean ALT-F4?
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
If My.Computer.Keyboard.AltKeyDown Then e.Cancel = True
End Sub
Or even shorter;
e.Cancel=My.Computer.Keyboard.AltKeyDown