GRChandrashekar
asked on
C# trigger button click on function key press
Hi, I am Developing C# winform Application. I need to use function keys to trigger button click event. for that I have written code as below.
My Problem is I do not want to write this code in every form, instead write a class file for this and call the same from the form.
Request help on
1. How to convert to class file.
2. How to call from the form.
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.F))
{
button1.PerformClick();
}
return base.ProcessCmdKey(ref msg, keyData);
}
My Problem is I do not want to write this code in every form, instead write a class file for this and call the same from the form.
Request help on
1. How to convert to class file.
2. How to call from the form.
ASKER
Any idea how to use IMessageFilter() in a class file
Do you want button1 on the current form to be run?...or will each form have different actions/buttons?
ASKER
Each form button name will be same like
btnsave
btnclose
btndelete
btnclear
btnsave
btnclose
btndelete
btnclear
Try this out then. I've given the code for simply F1 corresponding to clicking on btnSave. It correctly clicked btnSave on the active form (either Form1 or Form2 in this example):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MyFilter mf = new MyFilter();
mf.F1 += new MyFilter.dlgF1(mf_F1);
Application.AddMessageFilter(mf);
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Show();
}
private void btnSave_Click(object sender, EventArgs e)
{
MessageBox.Show("Form1.btnSave");
}
private void mf_F1()
{
Form frm = Form.ActiveForm;
if (frm != null)
{
Control[] matches = frm.Controls.Find("btnSave", true);
if (matches.Length > 0 && matches[0] is Button)
{
Button btn = (Button)matches[0];
btn.PerformClick();
}
}
}
}
public class MyFilter : IMessageFilter
{
public delegate void dlgF1();
public event dlgF1 F1;
private const int WM_KEYUP = 0x101;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_KEYUP)
{
Keys key = (Keys)(int)m.WParam & Keys.KeyCode;
if (key == Keys.F1)
{
if (F1 != null)
{
F1();
return true;
}
}
}
return false;
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void btnsave_Click(object sender, EventArgs e)
{
MessageBox.Show("Form2.btnSave");
}
}
ASKER
Well, without using Form1 and Form2, if I need to implement this directly in Form 2 having save button how can I do this
Not sure I follow. If Form2 is active, then the btnSave button on Form2 will be clicked. Whatever is coded for that button will run.
You don't need to make any changes on Form2 for this to happen.
You don't need Form1 either. Basically whatever form is the "startup form" needs to register the MessageFilter with this code:
Then, in that same form, it needs to handle the F1 event:
You don't need to make any changes on Form2 for this to happen.
You don't need Form1 either. Basically whatever form is the "startup form" needs to register the MessageFilter with this code:
MyFilter mf = new MyFilter();
mf.F1 += new MyFilter.dlgF1(mf_F1);
Application.AddMessageFilter(mf);
Then, in that same form, it needs to handle the F1 event:
private void mf_F1()
{
Form frm = Form.ActiveForm;
if (frm != null)
{
Control[] matches = frm.Controls.Find("btnSave", true);
if (matches.Length > 0 && matches[0] is Button)
{
Button btn = (Button)matches[0];
btn.PerformClick();
}
}
}
ASKER
Sorry need little more detail.
My solution start up form is LoginForm.
My form which has btnsave is titleform.
So you mean i need to the following in login form
and then in titleform I add this ?
My solution start up form is LoginForm.
My form which has btnsave is titleform.
So you mean i need to the following in login form
MyFilter mf = new MyFilter();
mf.F1 += new MyFilter.dlgF1(mf_F1);
Application.AddMessageFilter(mf);
and then in titleform I add this ?
private void mf_F1()
{
Form frm = Form.ActiveForm;
if (frm != null)
{
Control[] matches = frm.Controls.Find("btnSave", true);
if (matches.Length > 0 && matches[0] is Button)
{
Button btn = (Button)matches[0];
btn.PerformClick();
}
}
}
The two need to be in the same form together.
That form should be one that stays "alive" for the entire app. If you close the login form then it might make more sense to put that code into the title form (assuming you don't need those shortcuts while the login form is open).
That form should be one that stays "alive" for the entire app. If you close the login form then it might make more sense to put that code into the title form (assuming you don't need those shortcuts while the login form is open).
ASKER
Sorry for late response. Since my MDI form always remains open i have put the code as follows
The very first line IMessageFilter mf = new MyFilter(); shows error for MyFilter. Error:Cannot resolve symbol "MyFilter"
private void MdiParentLoad(object sender, EventArgs e)
{
IMessageFilter mf = new MyFilter();
mf.F1 += new MyFilter.dlgF1(MfF1);
Application.AddMessageFilter(mf);
}
private static void MfF1()
{
var frm = ActiveForm;
if (frm != null)
{
var matches = frm.Controls.Find("btnSave", true);
if (matches.Length > 0 && matches[0] is Button)
{
var btn = (Button)matches[0];
btn.PerformClick();
}
}
}
The very first line IMessageFilter mf = new MyFilter(); shows error for MyFilter. Error:Cannot resolve symbol "MyFilter"
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
buttons we're clicking only in the MdiChildren?
ASKER
WOW ! Works like a charm. Great is that person who invented this site and greatest are experts like you :)
Before I close this question I last help is needed.
If I have add another one like F2 for btndelete how can I do that? after I learn this i can go on adding further :)
Hope you wont mind answering this last question of mine
Before I close this question I last help is needed.
If I have add another one like F2 for btndelete how can I do that? after I learn this i can go on adding further :)
Hope you wont mind answering this last question of mine
Follow the pattern in MyFilter and declare another event for "F2":
Then add a check for F2 in PreFilterMessage():
Finally, in the MdiParent form, you need to wire up that new event and handle it accordingly:
*Note that the controls names are case-sensitive so if your button is named "btnDelete" and you search for "btndelete" then it won't work.
public delegate void dlgF1();
public event dlgF1 F1;
public delegate void dlgF2();
public event dlgF2 F2;
Then add a check for F2 in PreFilterMessage():
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_KEYUP)
{
Keys key = (Keys)(int)m.WParam & Keys.KeyCode;
if (key == Keys.F1)
{
if (F1 != null)
{
F1();
return true;
}
}
else if (key == Keys.F2)
{
if (F2 != null)
{
F2();
return true;
}
}
}
return false;
}
Finally, in the MdiParent form, you need to wire up that new event and handle it accordingly:
private void MdiParentLoad(object sender, EventArgs e)
{
MyFilter mf = new MyFilter();
mf.F1 += new MyFilter.dlgF1(MfF1);
mf.F2 += new MyFilter.dlgF1(MfF2);
Application.AddMessageFilter(mf);
}
private void MfF1()
{
var frm = this.ActiveMdiChild;
if (frm != null)
{
var matches = frm.Controls.Find("btnSave", true);
if (matches.Length > 0 && matches[0] is Button)
{
var btn = (Button)matches[0];
btn.PerformClick();
}
}
}
private void MfF2()
{
var frm = this.ActiveMdiChild;
if (frm != null)
{
var matches = frm.Controls.Find("btndelete", true);
if (matches.Length > 0 && matches[0] is Button)
{
var btn = (Button)matches[0];
btn.PerformClick();
}
}
}
*Note that the controls names are case-sensitive so if your button is named "btnDelete" and you search for "btndelete" then it won't work.
**You could make a function that receives the control name and returns the matching control. That would make the code shorter and reduce the repetition.
ASKER
You mean make function for this line var matches = frm.Controls.Find("btnSave ", true);
This whole snippet can be its own function as it is repeated and the only difference is the string used for the button name:
var frm = this.ActiveMdiChild;
if (frm != null)
{
var matches = frm.Controls.Find("btndelete", true);
if (matches.Length > 0 && matches[0] is Button)
{
var btn = (Button)matches[0];
btn.PerformClick();
}
}
ASKER
Wish I could award even more points :) excellent guidance.
Realistically, though, that amount of code is trivial, and you're going to need code in every form anyways to receive any kind of notification for function keys!...regardless of where/how they are trapped.