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.Windows.Forms.KeyEventArgs)
C#
System.Windows.Forms.Control.ProcessKeyEventArgs(ref
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.OnMessage(ref
System.Windows.Forms.Message) C#
System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref
System.Windows.Forms.Message) C#
System.Windows.Forms.NativeWindow.DebuggableCallback(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.FPushMessageLoop(int, int, int) C#
System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int,
System.Windows.Forms.ApplicationContext) C#
System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int,
System.Windows.Forms.ApplicationContext) C#
System.Windows.Forms.Application.Run(System.Windows.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/subscriptions/managednewsgroups/default.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/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no