By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,187 Members | 1,046 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,187 IT Pros & Developers. It's quick & easy.

ContextMenuStrip and PreviewKeyDown

P: n/a
How do I get my ContextMenuStrip to receive key down preview events? I have
the event hooked but I don't see the key strokes in the event?

Dave
Jan 31 '07 #1
Share this Question
Share on Google+
7 Replies


P: n/a
Put a combo box in the menu and key digits into it, you will notice your key
preview is not getting the keystrokes
""Jeffrey Tan[MSFT]"" <je***@online.microsoft.comwrote in message
news:hn****************@TK2MSFTNGHUB02.phx.gbl...
Hi Dave,

Based on my understanding, you are registering
ContextMenuStrip.PreviewKeyDown event in Winform application, however,
your
event is never fired.

Can you tell me how do you try to fire this event? Based on my research,
ContextMenuStrip.PreviewKeyDown actually inherits from Control class. In
Control.PreviewKeyDown MSDN document, we will read: "Occurs when a key is
pressed while the control has focus". So, this event will be fired when
the
control has focus. Note: in this scenario, the control means the
ContextMenuStrip instead of the control the ContextMenuStrip associated
with. In my test project, I right click on the associated control to show
out the ContextMenuStrip, and then I pressed the keyboard, the
ContextMenuStrip.PreviewKeyDown event will fire without any problem. You
may give these steps a try.

I have attached the sample project in this reply(you may use Outlook
Express to download it), for your information.

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscripti...ult.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscripti...t/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no
rights.
Feb 1 '07 #2

P: n/a
Hi Dave,

Thanks for your feedback.

Yes, I can reproduce this behavior. Actually, this is expected. After
adding a ToolStripCombobox into the ContextMenuStrip, when you are typing
in the combobox edit textbox, there is actually another child control in
ContextMenuStrip control, that is the Combobox. So the keydown notification
will not be sent to its parent control, but to the direct child
control--ComboBox.(This makes sense, for example, when you are typing in
the ContextMenuStrip, you do not want its parent control(Form)'s
PreviewKeyDown event to be called. )

To resolve this problem, you may get the reference to the Combobox and
register its PreviewKeyDown like below:

private void Form1_Load(object sender, EventArgs e)
{
this.toolStripComboBox1.ComboBox.PreviewKeyDown += new
PreviewKeyDownEventHandler(ComboBox_PreviewKeyDown );
}

void ComboBox_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
MessageBox.Show("ComboBox_PreviewKeyDown");
}

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscripti...ult.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscripti...t/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Feb 2 '07 #3

P: n/a
I was hoping to not have to do that. Is there no functionality similar to
the KeyPreview property of a form on a ContextMenuStrip?

In all the history of windows any parent window is capable of hooking the
keyboard events of it's child window.

In my case this Context menu is an abstract class and has dozens of custom
controls with dozens of controls on the custom control. I would eventually
have to create hundreds of key event handlers. Which is not my preferred
way of doing this.

I guess I need to create some sort of popup window similar to
ContextMenuStrip that is based on a form class so I can turn on KeyPreview.
Any suggestions?

Dave
""Jeffrey Tan[MSFT]"" <je***@online.microsoft.comwrote in message
news:2Z**************@TK2MSFTNGHUB02.phx.gbl...
Hi Dave,

Thanks for your feedback.

Yes, I can reproduce this behavior. Actually, this is expected. After
adding a ToolStripCombobox into the ContextMenuStrip, when you are typing
in the combobox edit textbox, there is actually another child control in
ContextMenuStrip control, that is the Combobox. So the keydown
notification
will not be sent to its parent control, but to the direct child
control--ComboBox.(This makes sense, for example, when you are typing in
the ContextMenuStrip, you do not want its parent control(Form)'s
PreviewKeyDown event to be called. )

To resolve this problem, you may get the reference to the Combobox and
register its PreviewKeyDown like below:

private void Form1_Load(object sender, EventArgs e)
{
this.toolStripComboBox1.ComboBox.PreviewKeyDown += new
PreviewKeyDownEventHandler(ComboBox_PreviewKeyDown );
}

void ComboBox_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
MessageBox.Show("ComboBox_PreviewKeyDown");
}

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscripti...ult.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscripti...t/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no
rights.
>

Feb 2 '07 #4

P: n/a
Did you manually edit the designer get contextMenuStrip1 constructed like
this?

this.contextMenuStrip1 = new
ContextMenuStripTest.Form1.MyContextMenuStrip(this .components);


""Jeffrey Tan[MSFT]"" <je***@online.microsoft.comwrote in message
news:c$**************@TK2MSFTNGHUB02.phx.gbl...
Hi Dave,

Thanks for your feedback!

Yes, I understand your concern. However, this is somewhat the limitation
of
Windows control keyboard input model.

Net Winform encapsulates the Win32 Windows controls, such as Edit
control(TextBox), Combobox, ListView, Button etc..., so it also obeys the
Win32 control message model and input model. In Windows control keyboard
input model, the WM_KEYDOWN messages(which maps to .Net Control.KeyDown
event) will only be sent to the control currently has focus. It will not
be
sent to this focused control's parent window or sibling window("window" is
the same concept as "control"). So if we type in the TextBox, the Windows
GUI system will not notify the parent Form class.

Yes, I see the Form.KeyPreview property. Let's research how this property
is implemented. Below is the stack trace I captured when Form.KeyPreview
property is set to true while I pressed a key on the focused button:
ContextMenuStripTest.Form1.Form1_KeyDown(object,
System.Windows.Forms.KeyEventArgs) C#
System.Windows.Forms.Control.OnKeyDown(System.Wind ows.Forms.KeyEventArgs)
C#
System.Windows.Forms.Control.ProcessKeyEventArgs(r ef
System.Windows.Forms.Message) C#
System.Windows.Forms.Form.ProcessKeyPreview(ref
System.Windows.Forms.Message) C#
System.Windows.Forms.Control.ProcessKeyMessage(ref
System.Windows.Forms.Message) C#
System.Windows.Forms.Control.WmKeyChar(ref System.Windows.Forms.Message)
C#
System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message)
C#
System.Windows.Forms.ButtonBase.WndProc(ref
System.Windows.Forms.Message)
C#
System.Windows.Forms.Button.WndProc(ref System.Windows.Forms.Message) C#
System.Windows.Forms.Control.ControlNativeWindow.O nMessage(ref
System.Windows.Forms.Message) C#
System.Windows.Forms.Control.ControlNativeWindow.W ndProc(ref
System.Windows.Forms.Message) C#
System.Windows.Forms.NativeWindow.DebuggableCallba ck(System.IntPtr, int,
System.IntPtr, System.IntPtr) C#
[Native to Managed Transition]
[Managed to Native Transition]

System.Windows.Forms.Application.ComponentManager. System.Windows.Forms.Unsaf
eNativeMethods.IMsoComponentManager.FPushMessageLo op(int, int, int) C#
System.Windows.Forms.Application.ThreadContext.Run MessageLoopInner(int,
System.Windows.Forms.ApplicationContext) C#
System.Windows.Forms.Application.ThreadContext.Run MessageLoop(int,
System.Windows.Forms.ApplicationContext) C#
System.Windows.Forms.Application.Run(System.Window s.Forms.Form) C#
ContextMenuStripTest.Program.Main() C#

As you can see, it is the Button.WndProc that calls base.WndProc which
finally calls Form.ProcessKeyPreview. Below is the source code of
Form.ProcessKeyPreview method:

protected override bool ProcessKeyPreview(ref Message m)
{
if ((this.formState[Form.FormStateKeyPreview] != 0) &&
this.ProcessKeyEventArgs(ref m))
{
return true;
}
return base.ProcessKeyPreview(ref m);
}

Yes, this method is the key point. This method checks if Form.KeyPreview
property is true, if so, it will call Control.ProcessKeyEventArgs() method
to dispatch the Button's KeyDown event to Form.KeyDown event. So, it is
still only the Button.WndProc receives the WM_KEYDOWN message, but .Net
Winform internally dispatch this message to Form.KeyDown event for
processing.

To satisfy your scenario, I inherit from ContextMenuStrip and simulate
what
Form.ProcessKeyPreview() method internal does, like below:

public class MyContextMenuStrip : ContextMenuStrip
{
public MyContextMenuStrip(IContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
container.Add(this);
}

public bool KeyPreview = false ;
protected override bool ProcessKeyPreview(ref Message m)
{
if ((this.KeyPreview== true) && this.ProcessKeyEventArgs(ref m))
{
return true;
}
return base.ProcessKeyPreview(ref m);
}
}

Now, in the Form designer, I change all the
System.Windows.Forms.ContextMenuStrip class to "MyContextMenuStrip" class
and register the contextMenuStrip1.KeyDown, like below:

private MyContextMenuStrip contextMenuStrip1;
this.contextMenuStrip1 = new
ContextMenuStripTest.Form1.MyContextMenuStrip(this .components);

private void Form1_Load(object sender, EventArgs e)
{
this.contextMenuStrip1.KeyPreview = true;
this.contextMenuStrip1.KeyDown += new
KeyEventHandler(contextMenuStrip1_KeyDown);
}

void contextMenuStrip1_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show("contextMenuStrip1_KeyDown");
}

Based on my test, this will have the same function as Form.KeyPreview
property. All the key down in the child controls of MyContextMenuStrip
will
first trigger MyContextMenuStrip.KeyDown. I hope this meets your need.

I have also attached the sample project in this reply. You may download it
through Outlook Express(can not use IE).

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscripti...ult.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscripti...t/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no
rights.
Feb 5 '07 #5

P: n/a
Jeffery,

Thanks for all your suggestions. With the information you gave me I was
able to make a single modification to my abstract class to solve the
problem.

Dave
""Jeffrey Tan[MSFT]"" <je***@online.microsoft.comwrote in message
news:c$**************@TK2MSFTNGHUB02.phx.gbl...
Hi Dave,

Thanks for your feedback!

Yes, I understand your concern. However, this is somewhat the limitation
of
Windows control keyboard input model.

Net Winform encapsulates the Win32 Windows controls, such as Edit
control(TextBox), Combobox, ListView, Button etc..., so it also obeys the
Win32 control message model and input model. In Windows control keyboard
input model, the WM_KEYDOWN messages(which maps to .Net Control.KeyDown
event) will only be sent to the control currently has focus. It will not
be
sent to this focused control's parent window or sibling window("window" is
the same concept as "control"). So if we type in the TextBox, the Windows
GUI system will not notify the parent Form class.

Yes, I see the Form.KeyPreview property. Let's research how this property
is implemented. Below is the stack trace I captured when Form.KeyPreview
property is set to true while I pressed a key on the focused button:
ContextMenuStripTest.Form1.Form1_KeyDown(object,
System.Windows.Forms.KeyEventArgs) C#
System.Windows.Forms.Control.OnKeyDown(System.Wind ows.Forms.KeyEventArgs)
C#
System.Windows.Forms.Control.ProcessKeyEventArgs(r ef
System.Windows.Forms.Message) C#
System.Windows.Forms.Form.ProcessKeyPreview(ref
System.Windows.Forms.Message) C#
System.Windows.Forms.Control.ProcessKeyMessage(ref
System.Windows.Forms.Message) C#
System.Windows.Forms.Control.WmKeyChar(ref System.Windows.Forms.Message)
C#
System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message)
C#
System.Windows.Forms.ButtonBase.WndProc(ref
System.Windows.Forms.Message)
C#
System.Windows.Forms.Button.WndProc(ref System.Windows.Forms.Message) C#
System.Windows.Forms.Control.ControlNativeWindow.O nMessage(ref
System.Windows.Forms.Message) C#
System.Windows.Forms.Control.ControlNativeWindow.W ndProc(ref
System.Windows.Forms.Message) C#
System.Windows.Forms.NativeWindow.DebuggableCallba ck(System.IntPtr, int,
System.IntPtr, System.IntPtr) C#
[Native to Managed Transition]
[Managed to Native Transition]

System.Windows.Forms.Application.ComponentManager. System.Windows.Forms.Unsaf
eNativeMethods.IMsoComponentManager.FPushMessageLo op(int, int, int) C#
System.Windows.Forms.Application.ThreadContext.Run MessageLoopInner(int,
System.Windows.Forms.ApplicationContext) C#
System.Windows.Forms.Application.ThreadContext.Run MessageLoop(int,
System.Windows.Forms.ApplicationContext) C#
System.Windows.Forms.Application.Run(System.Window s.Forms.Form) C#
ContextMenuStripTest.Program.Main() C#

As you can see, it is the Button.WndProc that calls base.WndProc which
finally calls Form.ProcessKeyPreview. Below is the source code of
Form.ProcessKeyPreview method:

protected override bool ProcessKeyPreview(ref Message m)
{
if ((this.formState[Form.FormStateKeyPreview] != 0) &&
this.ProcessKeyEventArgs(ref m))
{
return true;
}
return base.ProcessKeyPreview(ref m);
}

Yes, this method is the key point. This method checks if Form.KeyPreview
property is true, if so, it will call Control.ProcessKeyEventArgs() method
to dispatch the Button's KeyDown event to Form.KeyDown event. So, it is
still only the Button.WndProc receives the WM_KEYDOWN message, but .Net
Winform internally dispatch this message to Form.KeyDown event for
processing.

To satisfy your scenario, I inherit from ContextMenuStrip and simulate
what
Form.ProcessKeyPreview() method internal does, like below:

public class MyContextMenuStrip : ContextMenuStrip
{
public MyContextMenuStrip(IContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
container.Add(this);
}

public bool KeyPreview = false ;
protected override bool ProcessKeyPreview(ref Message m)
{
if ((this.KeyPreview== true) && this.ProcessKeyEventArgs(ref m))
{
return true;
}
return base.ProcessKeyPreview(ref m);
}
}

Now, in the Form designer, I change all the
System.Windows.Forms.ContextMenuStrip class to "MyContextMenuStrip" class
and register the contextMenuStrip1.KeyDown, like below:

private MyContextMenuStrip contextMenuStrip1;
this.contextMenuStrip1 = new
ContextMenuStripTest.Form1.MyContextMenuStrip(this .components);

private void Form1_Load(object sender, EventArgs e)
{
this.contextMenuStrip1.KeyPreview = true;
this.contextMenuStrip1.KeyDown += new
KeyEventHandler(contextMenuStrip1_KeyDown);
}

void contextMenuStrip1_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show("contextMenuStrip1_KeyDown");
}

Based on my test, this will have the same function as Form.KeyPreview
property. All the key down in the child controls of MyContextMenuStrip
will
first trigger MyContextMenuStrip.KeyDown. I hope this meets your need.

I have also attached the sample project in this reply. You may download it
through Outlook Express(can not use IE).

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscripti...ult.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscripti...t/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no
rights.
Feb 5 '07 #6

P: n/a
Thanks I'll take a look at it.
""Jeffrey Tan[MSFT]"" <je***@online.microsoft.comwrote in message
news:K$**************@TK2MSFTNGHUB02.phx.gbl...
Hi Dave,

Thanks for your feedback!

Yes, in this little sample project, I did not move the MyContextMenuStrip
code into a separate control, so I just modified the original designer
generated code manually.

In practical using, you may move the code into a separate control, and
once
your control contains a constructor with the prototype below:
public MyContextMenuStrip(IContainer container)

The designer will understand it and generate the code to call this special
constructor:
this.myContextMenuStrip1 = new
ContextMenuStripTest.MyContextMenuStrip(this.compo nents);

The article below provides more details of the context of this
constructor:
"What's that "Windows Form Designer generated code" anyway?"
http://www.codeproject.com/dotnet/di...asp?print=true

I have also modified the original project to place the MyContextMenuStrip
code into a separate control. I have attached this sample project in this
reply, for your information.

Hope it helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscripti...ult.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscripti...t/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no
rights.
Feb 9 '07 #7

P: n/a
Ok, if you still need any help or have anything unclear, please feel free
to tell me, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscripti...ult.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscripti...t/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

Feb 12 '07 #8

This discussion thread is closed

Replies have been disabled for this discussion.