I need to catch the F1 KeyEvent when it fires regardless of what has current focus. Currently I have a base class that defines the method that is intended to fire upon F1 keyup. In the child class I am listening for the .KeyUp event and will invoke the parent.
//Base class:
protected void GetHelp(String helpIndexParam)
{
// Logic
}
//Child Class:
//Declared in constructor of child class
KeyPreview = true;
this.KeyUp += new System.Windows.Forms.KeyEventHandler(KeyEvent);
private void KeyEvent(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F1)
{
base.GetHelp("20");
}
}
Currently, a child form opens and I press F1, nothing happens. Only when I click on a control on the form and then press F1 does the GetHelp("") function execute.
Any suggestions appreciated. Cheers.
In this scenario, you may use ProcessCmdKey method in the parent form or each child form:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.F1) {
// Show help;
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
Or since you are looking for F1 key, you can use the HelpRequest event:
public Form1() {
InitializeComponent();
this.HelpRequested += Form1_HelpRequested;
}
private void Form1_HelpRequested(object sender, HelpEventArgs hlpevent) {
// Show Help
}
I was able to get it working. I learned that because we're using an MDI, the MDI itself was apparently consuming any attempt of catching an F1 click in the child form. I basically had to set it up so that the KeyUp event was defined in the parent form as opposed to the child form, and the child form would simply populate the needed properties from the parent form. That's how I was able to pass a the necessary info to the parent. Also, I had to set focus on a control on the child form just so the whole thing could come together.
I appreciate all the help guys. You all pointed me down the right path in the long run. Cheers.
Related
I have just found out that we can't use the KeyDown event directly with a PictureBox. So I have to change my strategy.
I decided to add the Keydown event to the actual form:
private void FullColourPaletteForm_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Left:
{
MessageBox.Show("Left");
e.Handled = true;
return;
}
}
}
Doesn't get executed. I see no message box when I press the left allow. Instead (and rightly so) it just moves the cusor from control to control.
I was hoping to be able to mimic some kind of cursor support for the block of colour by intercepting the arrow keys inside the picture box.
I am not sure of the best way forward. I don't want to break the standard dialogue functionality of moving between controls, but I want to now include suipport for detectign keys so I can add my code to move my block of colour.
Can it be done? Not sure why my event is not getting triggered in the form anyway.
I saw this question. So I tried setting my form KeyPreview property. No joy. I also looked at ProcessCmdKey but it doesn't seem right for the issue in hand.
Update:
If I try to follow the idea in the comments and create a SelectablePictureBox control, it looks like this:
I have two issues. 1. I still can't seem to work out how to handle the keydown event on my pictureBox object itself. I am reluctant to manually add any handlers to the designer file incase my changes get lost.
Also, when doing general control nagivation on the form with cursor keys it does not seem to know about this control.
If you want to handle arrow keys at form level, you can override the form's ProcessCmdKey function this way:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Left)
{
MessageBox.Show("Left");
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
But in general it's better to create a custom paint selectable control like this rather than putting such logic at form level. Your control should contain such logic.
Note
OP: I have just found out that we can't use the KeyDown event directly
with a PictureBox
As mentioned by Hans in comments, the PictureBox control is not selectable and can not be focused by default and you can not handle keyboard events for the control.
But you can force it to be selectable and support keyboard events this way:
using System;
using System.Reflection;
using System.Windows.Forms;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.pictureBox1.SetStyle(ControlStyles.Selectable, true);
this.pictureBox1.SetStyle(ControlStyles.UserMouse, true);
this.pictureBox1.PreviewKeyDown +=
new PreviewKeyDownEventHandler(pictureBox1_PreviewKeyDown);
}
void pictureBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyData == Keys.Left)
MessageBox.Show("Left");
}
}
public static class Extensions
{
public static void SetStyle(this Control control, ControlStyles flags, bool value)
{
Type type = control.GetType();
BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
MethodInfo method = type.GetMethod("SetStyle", bindingFlags);
if (method != null)
{
object[] param = { flags, value };
method.Invoke(control, param);
}
}
}
At least knowing this approach as a hack you can reuse the extension method to enable or disable some styles on controls in future.
I have a Leave Event for a TextEditor in which I perform a validation that an entry is required and display an error message.
Before I perform the validation, I check if the form is disposing, or the Cancel button was clicked. In that case I exit the leave event.
But if the user clicks the X button, these two checks do not capture that and the error message is displayed. I do not want the error message to display if the user clicks the X button. How can I achieve that?
private void TitleTextEditor_Leave(object sender, EventArgs e)
{
UltraTextEditor _currentControl = sender as UltraTextEditor;
if (this.CancelUButton.Focused || this.Disposing)
{
return;
}
if (_currentControl.Text.IsNullOrStringEmpty())
{
MessageBox.Show("Title is required.");
}
}
This is a cruddy problem if you want to suppress the validation error message you display. The only decent way to get ahead of it is by detecting the WM_CLOSE message before the Winforms code sees it and generates the Validating event on the control with the focus.
Paste this code to solve your problem:
protected override void WndProc(ref Message m) {
// Prevent validation on close:
if (m.Msg == 0x10) this.AutoValidate = AutoValidate.Disable;
base.WndProc(ref m);
}
Do consider that you are yelling too loud. The ErrorProvider component is a very decent way to display validation errors and be subtle about it. And nothing drastic goes wrong when the form validates itself on closure, you only have to do this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
e.Cancel = false;
}
In the FormClosingEventArgs you have a CloseReason property, you can probably use it.
How to find out if a control's Form has closed or not. I have listened to the VisibleChanged event in order to divine the Form because ParentChanged can happen before the control is added to a Form (e.g. if it is in a Panel). You might also want to unsubscribe from VisibleChanged events after the first one.
//put this at class level
bool _parentClosed;
//put this in controls constructor
//when control first becomes visible
this.VisibleChanged += (s1, a1) =>
{
//find parent Form (not the same as Parent)
Form form = this.FindForm();
//If we are on a Form
if (form != null)
//subscribe to it's closing event
form.Closing += (s2, a2) => { _parentClosed = true; };
else
throw new Exception("How did we become visible without being on a Form?");
};
I have UserControl and facing problem of KeyDown Event. My UserControls will shows against revoke of windows forms keydown event like below:
User Control’s Event:
private void UserControl_KeyDown(object sender,KeyEventArgs e)
{
if ((Keys)e.KeyCode == Keys.Escape)
{
this.Visible = false;
}
}
The above event will have to hide the UserControl but the event not fire due to revoke of windows forms keydown as below:
Windows Form:
private void button1_Click(object sender, EventArgs e)
{
panel1.SendToBack();
panel2.SendToBack();
panel3.SendToBack();
panel4.SendToBack();
am.Focus();
this.KeyDown -= new KeyEventHandler(Form1_KeyDown);
}
This will shows the UserControls as the UserControls are added to windows forms by as below:
private UserControl.UserControl am = new UserControl.UserControl();
public Form1()
{
InitializeComponent();
this.Controls.Add(am);
}
I want to revoke the keydown event of winform against visible of UserControl and fire the keydown event of UserControl for hide the UserControl but it’s not doing well. The keydown event of UserControl event is not fire. Don’t know why?. How to do the same in proper way?.
Keyboard notifications are posted to the control with the focus. Which is almost never a UserControl, it doesn't want the focus. Even if you explicitly set the focus with the Focus() method, it will immediately pass it off to one of its child controls. UserControl was designed to be just a container for other controls.
Override the ProcessCmdKey() method instead. Paste this code into the control class:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.Escape) {
this.Visible = false;
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
Beware that using the Escape key is not the greatest idea, the Form you put your user control on may well have a need for that key. Like a dialog.
I'm trying the get the inputted values from the user and save it on a char variable, but the problem is that nothing occurs, and I think the problem is with the Form Focus, this is the code, and when I run it no errors occurs, but also nothing happen. What I did wrong?
char keyPressed;
public FrmZigndSC()
{
InitializeComponent();
this.Focus();
}
private void FrmZigndSC_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
keyPressed = e.KeyChar;
LblResult.Text += Convert.ToString(keyPressed);
}
You can try with this code - Based on KeyPressEventHandler
public FrmZigndSC()
{
InitializeComponent();
this.Focus();
//Subscribe to event
this.KeyPress += new KeyPressEventHandler(FrmZigndSC_KeyPress);
}
private void FrmZigndSC_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
keyPressed = e.KeyChar;
LblResult.Text += Convert.ToString(keyPressed);
// Indicate the event is handled.
e.Handled = true;
}
If you want to recieve a key notification from the application'e mesage pipeline, relaying on focus of the element, in this case, make architecture fragile. You can not gurantee that from other forms in your app that one would be focused, or the form is nto covered by some control that absorbes that event. You can not forse to a form having a focus, cause it's completely bad UX design (not very sure even if this is possible to implement in 100% working way).
What you can do it, instead, is declare class derived from IMessageFilter:
public class MessageFilter : IMessageFilter
{
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
public bool PreFilterMessage(ref Message m)
{
// Intercept KEY down message
Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode;
if ((m.Msg == WM_KEYDOWN)
{
//get key pressed
return true;
}
else
{
return false;
}
}
}
and after register it within your application:
MessageFilter filter = new MessageFilter(); //init somewhere
Application.AddMessageFilter(filter ); // add
.....
//on application end don't forget to remove it
Application.RemoveMessageFilter(filter );
I tried to reproduce it in an empty little Windows Forms project. This code worked just fine without the Shown event handler:
public partial class FrmZigndSC : Form
{
public FrmZigndSC()
{
InitializeComponent();
this.KeyPress += (s, e) => this.LblResult.Text += e.KeyChar.ToString();
// this might be a solution, but i did not need it
this.Shown += (s, e) => this.Activate();
}
}
You could try to use this.Activate() anyway and see if it helps. If you got other input controls such as text boxes on your form, try setting the form's KeyPreview property to true.
Using the FocusManager instead of this.Focus() should do the trick!
http://msdn.microsoft.com/en-us/library/system.windows.input.focusmanager.aspx
I Think the problem is that when you have differenct controls on your Form that catch ketpressed. I had the same probmel with an DateTimePicker on my control.
Try to delete all of them and then try it, it will work. And from that point add the controls again to see which on is the problem.
The code you have given is working fine for me. Set the startup page as FrmZigndSC and try again.
I'd like a context menu on the caption bar right click
any tips/samples pref in c# ?
UPDATE - for various reasons, right click on the form won't work because the form is not empty and the form is composited dynamically so....
You can do this by trapping the WM_NCRBUTTONDOWN notification that Windows sends when the user right-clicks the title bar. The control class does not have an event for it, you'll need to override WndProc(). Here's an example form, you'll need to add a ContextMenuStrip:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected void OnTitlebarClick(Point pos) {
contextMenuStrip1.Show(pos);
}
protected override void WndProc(ref Message m) {
const int WM_NCRBUTTONDOWN = 0xa4;
if (m.Msg == WM_NCRBUTTONDOWN) {
var pos = new Point(m.LParam.ToInt32());
OnTitlebarClick(pos);
return;
}
base.WndProc(ref m);
}
}
MSDN explains how to handle right-clicks on Windows Forms controls. Controls, including Forms, inherit the MouseClick event.
MouseEventArgs will tell you what button was clicked through the Button property. Have a look at the MouseButtons Enumeration.
if you handle the form mouse-click, you can then use the following code:
private void Dialog_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.Text = "new caption text";
}
}
But you'll have to make sure that you generate this event for the top-level control on a form. For instance if you have a group box on the form, it will receive the mouse-click events rather than the form itself, for the areas of the form that are under the group box.
There is already a menu managed by Windows when you right-click the titlebar.
Do you want to replace it completely?
If you want to add to it you will have to use the Win32 API and interop and you will have to subclass the form.
See the AppendMenu() function.
Basically you need to use p-invoke to do this. There is a really great example at Here
You can see from the example you will need to manually mimic the event handlers, but this is pretty straight forward.
You can override WndProc of the form and capture the WM_NCRBUTTONDOWN message:
protected override void WndProc(ref Message m)
{
const int WM_NCRBUTTONDOWN = 0xA4;
if (m.Msg == WM_NCRBUTTONDOWN)
{
MessageBox.Show("Caption right clicked!");
}
else
{
base.WndProc(ref m);
}
}
This code will suppress the window's context menu, however. You may not wish this. The WM_NCRBUTTONDOWN message will also be sent if you right click the window borders as well. You may not desire this either.