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.

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        if (keyData == (Keys.Control | Keys.F))
        {
            button1.PerformClick();
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }

Open in new window


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.
GRChandrashekarAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Mike TomlinsonMiddle School Assistant TeacherCommented:
You could use IMessageFilter() to trap the Function keys and Form.ActiveForm to grab the current form.  If you make all the forms implement a custom Interface then you can send the keystroke to a special method that decides what to do with it.

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.
0
GRChandrashekarAuthor Commented:
Any idea how to use IMessageFilter()  in a class file
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
Do you want button1 on the current form to be run?...or will each form have different actions/buttons?
0
Build an E-Commerce Site with Angular 5

Learn how to build an E-Commerce site with Angular 5, a JavaScript framework used by developers to build web, desktop, and mobile applications.

GRChandrashekarAuthor Commented:
Each form button name will be same like

btnsave
btnclose
btndelete
btnclear
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
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();
                }
            }
        }

    }

Open in new window

    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; 
        }

    }

Open in new window

    public partial class Form2 : Form
    {

        public Form2()
        {
            InitializeComponent();
        }

        private void btnsave_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Form2.btnSave");
        }

    }

Open in new window

0
GRChandrashekarAuthor Commented:
Well, without using Form1 and Form2, if I need to implement this directly in Form 2 having save button how can I do this
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
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:
            MyFilter mf = new MyFilter();
            mf.F1 += new MyFilter.dlgF1(mf_F1);
            Application.AddMessageFilter(mf);

Open in new window


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();
                }
            }
        }

Open in new window

0
GRChandrashekarAuthor Commented:
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

  MyFilter mf = new MyFilter();
            mf.F1 += new MyFilter.dlgF1(mf_F1);
            Application.AddMessageFilter(mf);

Open in new window


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();
                }
            }
        }

Open in new window

0
Mike TomlinsonMiddle School Assistant TeacherCommented:
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).
0
GRChandrashekarAuthor Commented:
Sorry for late response. Since my MDI form always remains open i have put the code as follows

     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();
                }
            }
        }

Open in new window


The very first line IMessageFilter mf = new MyFilter(); shows error for MyFilter. Error:Cannot resolve symbol "MyFilter"
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
You need to add the MyFilter class from back here:
http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_28267116.html#a39574283

Also, you didn't mention anything about MDI before.  That's kind of important!

Are the buttons we're clicking only in the MdiChildren?  Or will other non-MDI forms be open (besides the main MdiParent) with these buttons?

You can't declare the filter as IMessageFilter as then you wont' be able to wire up the custom event.  Declare it as MyFilter instead.  Also, "MfF1" can't be static as you then won't be able to access the active form property.  Why did you change it so much?...

All together it should look more like below.  Note that it's using ActiveMdiChild now instead of ActiveForm:
    public partial class MdiParent : Form
    {
        public MdiParent()
        {
            InitializeComponent();
        }

        private void MdiParentLoad(object sender, EventArgs e)
        {
            MyFilter mf = new MyFilter();
            mf.F1 += new MyFilter.dlgF1(MfF1);
            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();
                }
            }
        }

    }

    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;
        }
    }

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
GRChandrashekarAuthor Commented:
buttons we're clicking only in the MdiChildren?
0
GRChandrashekarAuthor Commented:
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
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
Follow the pattern in MyFilter and declare another event for "F2":
        public delegate void dlgF1();
        public event dlgF1 F1;

        public delegate void dlgF2();
        public event dlgF2 F2;

Open in new window


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;
        }

Open in new window


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();
                }
            }
        }

Open in new window


*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.
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
**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.
0
GRChandrashekarAuthor Commented:
You mean make function for this line var matches = frm.Controls.Find("btnSave", true);
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
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();
                }
            }

Open in new window

0
GRChandrashekarAuthor Commented:
Wish I could award even more points :) excellent guidance.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.