Adding an F5 Hotkey in C# - c#

I'm making a windows app (WinForms) and would like my application to call a method when the user presses F5 - this should work no matter what the user is doing but they must be using the program - I don't want to use global hooks - any ideas?

Override the form's ProcessCmdKey on your main form and look for F5.
protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
{
bool bHandled = false;
// switch case is the easy way, a hash or map would be better,
// but more work to get set up.
switch (keyData)
{
case Keys.F5:
// do whatever
bHandled = true;
break;
}
return bHandled;
}

Check out the Form.KeyPreview property, it will allow you to trap all KeyDown, KeyUp and KeyPress events at the form level before allowing them to be processed by individual elements.
MSDN Form.KeyPreview page

If you have only one form that can have focus, you can set the KeyPreview property of that form to true and handle the KeyPress event.
The KeyPreview property will cause the form to receive all key presses, regardless which control on the form has the input focus.

Related

How do I capture Keys.F1 regardless of the focused control on a form?

I used KeyDown event and some simple code like if (e.KeyCode == Keys.F1) to capture F1 is pressed on a form BUT if there are some text boxes on the form or if there are some spreadsheets with Dock Fill on the form then the code above gets useless and does nothing. But I want to do something when user presses F1 on this form. so how do we capture a specific keydown event like F1 on the whole form..and I do not want to go to the route that capture the KeyDown of all other controls on the form and pass them to the Form for processing. is there any cleaner way to do this?
Yes, indeed there is. The correct way for the form to handle key events regardless of the control that currently has the input focus is to override the ProcessCmdKey method of your form class:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.F1)
{
MessageBox.Show("You pressed the F1 key");
return true; // indicate that you handled this keystroke
}
// Call the base class
return base.ProcessCmdKey(ref msg, keyData);
}
You return true to indicate that you handled the keystroke and don't want it to be passed on to other controls. If you do want it to be passed on to the event handlers for other controls, simply return false.
And you're best off ignoring the KeyPreview property. That's an anachronism from the VB 6 days and not really the preferred way of doing this in the .NET world. Further reading: Disadvantage of setting Form.KeyPreview = true?
Set the form's KeyPreview to true. This will make sure the form get the keypress messages first and if you handle it, you can set e.Handled = true so it doesn't passed down to the controls.
Turn on KeyPreview and every key press in the form will get routed through it's key event handlers first.
Another way is to Override the ProcessCmdKey function http://msdn.microsoft.com/en-us/library/system.windows.forms.control.processcmdkey(v=VS.100).aspx

Fire Form KeyPress event

I have a C# winform, on which I have 1 button.
Now, when I run my application, the button gets focus automatically.
The problem is KeyPress event of my form does not work because the button is focused.
I have tried this.Focus(); on FormLoad() event, but still the KeyPress event is not working.
You need to override the ProcessCmdKey method for your form. That's the only way you're going to be notified of key events that occur when child controls have the keyboard focus.
Sample code:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
// look for the expected key
if (keyData == Keys.A)
{
// take some action
MessageBox.Show("The A key was pressed");
// eat the message to prevent it from being passed on
return true;
// (alternatively, return FALSE to allow the key event to be passed on)
}
// call the base class to handle other key events
return base.ProcessCmdKey(ref msg, keyData);
}
As for why this.Focus() doesn't work, it's because a form can't have the focus by itself. A particular control has to have the focus, so when you set focus to the form, it actually sets the focus to the first control that can accept the focus that has the lowest TabIndex value. In this case, that's your button.
Try setting the Form's KeyPreview property to True.
Set keyPreview = true on main form
I would use one of the following:
Set the TabIndex property of the button to 0.
Set the IsDefault property of the button to true - So, It will be fired when pressing the ENTER key.
I had this same problem and I know this question was answered long ago, but my solution to this problem came from another stack overflow question in which my only button grabbed and kept focus. I accepted the users advice and created a button which couldn't get focus.
Maybe someone will find this useful:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace I2c_Programmer {
class NoSelectButton : Button{
public NoSelectButton() {
SetStyle(ControlStyles.Selectable, false);
}
}
}
Go into your designer, where the button is created and switch out the new System...button with your new class "new NoSelectButton();"

Send Keyboard Events from one Form to another Form

my question is quite simple:
Our C# application has one MainForm with a menu and several keyboard shortcuts associated with the menu entries.
Now we need to trigger the menu entries from some child forms too. But since the MainForm is inactive when one of the child forms is active, the shortcuts do not work.
Is there a simple way to propagate all keyboard events from the child form to the 'Owner' form? Or just to another form in general?
Ah, and we cannot use some low level windows stuff, because we need to run the application on Mono/Linux too.
EDIT:
The exact problem i have is to trigger the menu items with the same shortcut from another form. Of course without updating code in the forms if the menu changes of new items are added.
This is what fixed it for me:
public class MainForm : Form
{
public bool ProcessCmdKeyFromChildForm(ref Message msg, Keys keyData)
{
Message messageCopy = msg;
messageCopy.HWnd = this.Handle; // We need to assign our own Handle, otherwise the message is rejected!
return ProcessCmdKey(ref messageCopy, keyData);
}
}
public class MyChildForm : Form
{
private MainForm mMainForm;
public MyChildForm(MainForm mainForm)
{
mMainForm = mainForm;
}
// This is meant to forward accelerator keys (eg. Ctrl-Z) to the MainForm
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (mMainForm.ProcessCmdKeyFromChildForm(ref msg, keyData))
{
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
Did you try something like this?
ParentForm : Form
{
public NotifyKeyPress(KeyPressEventArgs e)
{
OnKeyPress(e);
}
}
ChildForm : Form
{
ParentForm _parent;
public ChildForm(ParentForm parent)
{
_parent = parent;
KeyPress += KeyPressHandler;
}
public KeyPressHandler(object sender, KeyPressEventArgs e)
{
if (_parent != null)
{
_parent.NotifyKeyPress(e);
}
}
}
I think you want to set KeyPreview on the parent form to true
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. For example, if the KeyPreview property is set to true and the currently selected control is a TextBox, after the keystroke is handled by the event handlers of the form the TextBox control will receive the key that was pressed. 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.
EDIT:
the answer in this question might be helpful:
The ToolStrip.AllowMerge property "gets or sets [...] whether multiple MenuStrip, ToolStripDropDownMenu, ToolStripMenuItem, and other types can be combined." (MSDN).
This means that you can:
"Use the AllowMerge property to enable multiple-document interface (MDI) children to combine their respective menus in the MDI parent." (AllowMerge property, Remark, MSDN)
See also:
MergeAction
MergeIndex
This, I hope, will help you get what you want. Now, I don't know if this is proper to Windows Forms or if it shall work on Linux too once built.
I presume by inactive you mean that it doesn't have focus?
The cleanest way to do this is to have each form expose events that relate to their menus being manipulated. When you create the forms, subscribe them to each other (or from child to MainForm or whatever way the flow needs to go). When the menu is clicked, execute your extra event and the other form will receive this.
Does that help? I believe that this is better than trying to force a message manually as it will be self-documenting code that the forms need to react to each other.
A more "away from the problem" approach, do you need two forms or can you refactor the UI design?
There is much simpler way to do this. Menu items should trigger appropriate method calls.
Then you can call these methods anywhere in application.
Instead of binding key shortcuts to menu items on the main form you can create a custom key-processing method that reacts to the key shortcuts. Put this method in the main form. Then invoke this method from all child forms on a key event. #Adam Driscoll's code is much compatible with this approach.

Handle clipboard copy on UserControl

I have complex UserControl (grid, edit controls for grid, etc...) and I want handle CTRL+C keyboard shortcut, however I don't want disable a native functions by edit controls (textboxes, comboboxes, etc...). If the CTRL+C is not handled by other inner controls I want handle it by myself (copy whole row(s) from grid, etc...).
I tried override WndProc method in UserControl and check for WM_COPY and WM_COPYDATA, but it doesn't work. It works only on final target control (TextBox for example).
You can do this by overriding ProcessCmdKey(). Check if a text box has the focus. For example:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == (Keys.Control | Keys.C)) {
var box = this.ActiveControl as TextBoxBase;
if (box == null) {
// Do your stuff
MessageBox.Show("Copy!");
return true;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
What you are looking for is a way to bubble events raised by a child control up to its container so that you can handle those events at the User Control's level.
The automatic propagation of events across the control hierarchy is built into WPF and is called Routed Events. However this functionality is not available out of the box in Windows Forms, so you will have to implement your own solution.
Have a look at this SO question to get some inspiration.
Related resources:
How to route events in a Windows Forms application
I didn't try it out and i think it heavy depends on all the child controls, which are within your UserControl. But normally a keystroke is given to the actual control that has the focus. If it doesn't handle that keystroke (setting e.Handled = true), it would be bubble up to its parent and if that doesn't handle it, it would go further till it reaches the form and finally the limbus.
So if your child controls are properly written and they can't handle the given keystroke (e.g. Control + C) it should be easy to add a handler into your UserControl to the KeyDown event and do whatever you like.
Update
After reading your comments, i still think that the way shown by Enrico and me should be the correct one. So i think the problem is that if one of your 3rd party controls has the focus it is not able to handle the copy shortcut, but it sets the e.Handled = true leading to no further informations of the parent controls about the shortcut.
So at first you should contact your control vendor and send him a bug report about this wrong behaviour.
Alternative there exists another hacky way:
In your form you can set the KeyPreview to true and intercept the incoming key. Now you could check if within the ActiveControl is something that handles the shortcut correctly (maybe a check against a Dictionary<Type, bool> or a HashSet<Type> lackingControls) and just leave the function or do whatever you want and setting the e.Handled = true by yourself.
Update 2
A little snippet to illustrate what i meant:
this.KeyPreview = true;
HashSet<Type> scrappyControls = new HashSet<Type>();
//ToDo: Add all controls that say it handles Ctrl-C
// but doesn't it the right way.
scrappyControls.Add(typeof(TextBox));
this.KeyDown += (sender, e) =>
{
if (e.KeyData == (Keys.Control | Keys.C))
{
if (scrappyControls.Contains(this.ActiveControl.GetType()))
{
//ToDo: Do copy to clipboard on yourself
e.Handled = true;
}
}
};
The drawback of this functionality is, that it must be placed into your form, not into your self-written UserControl. But that way you will be informed, when a TextBox has the focus and Control + C is pressed within.

C#: Trouble with Form.AcceptButton

I have a form with an button which is set as the AcceptButton of the form. The form has several other controls. Now when I press Enter on other controls the form gets closed because of the accept button on the form. Same goes for CancelButton. How do I handle this. I tried hooking on to keypress keydown event of the form and controls. None works. Any work around for this?
Thanks a ton,
Datte
That is how the AcceptButton property works. It specifies the button that is automatically clicked whenever you press <Enter>.
If you don't want this behaviour, don't set it as the AcceptButton. There is no other reason to do it.
Not exactly sure about how you expect your form to function, but you could do something like the following to have a little more control over things:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Enter)
{
// do something
}
if (keyData == Keys.Escape)
{
// do something else
}
return base.ProcessCmdKey(ref msg, keyData);
}
You can remove AcceptButton from form and set the KeyPreview property on the form that'll handle its KeyDown event. There you can check for the Enter key and take the action accordingly.
This is one of the feature of the form i.e.
if button does not have a focus if you still want desired code to be executed when user click Enter...
Set the AcceptButton property of a form to allow users to click a button by pressing the ENTER even if the button does not have focus.
Regards.
Try This One In VB>net
If CType(Me.ActiveControl, Button).Name = Button1.Name Then
End If

Categories