C# 如何拥有主窗体';s菜单是否处理OwnedForms上的事件?

C# 如何拥有主窗体';s菜单是否处理OwnedForms上的事件?,c#,winforms,C#,Winforms,我有一个Main表单,上面有一个MenuStrip,我使用该MenuStrip打开新的表单,如下所示: var target = new Target(); target.Owner = this; target.Show(); 这正是我所希望的:表单总是显示在主表单的前面 我遇到的问题是,当其中一个拥有的表单s具有焦点时,我无法通过键盘访问菜单提示。我希望CTRL+S触发保存功能,就像当Main窗体具有焦点时一样 这可能吗?有没有更好的方法来解决这个问题?很抱歉耽搁了您,但是如果您仍然有问题

我有一个
Main
表单
,上面有一个
MenuStrip
,我使用该
MenuStrip
打开新的
表单
,如下所示:

var target = new Target();
target.Owner = this;
target.Show();
这正是我所希望的:
表单
总是显示在
表单
的前面

我遇到的问题是,当其中一个拥有的
表单
s具有焦点时,我无法通过键盘访问
菜单提示
。我希望CTRL+S触发保存功能,就像当
Main
窗体具有焦点时一样


这可能吗?有没有更好的方法来解决这个问题?

很抱歉耽搁了您,但是如果您仍然有问题或正在寻找其他方法,请参阅下面的内容

在主窗体中:

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        ChildForm child = new ChildForm();
        // KeyPreview can be set in the properties of the child form instead
        child.KeyPreview = true;
        child.KeyPressed += Child_KeyPressed;
        child.ShowDialog();
    }

    private void Child_KeyPressed(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.S)
        {
            // Save Pressed
        }
    }
}
然后在您的子表单中:

public partial class ChildForm : Form
{
    public event EventHandler<KeyEventArgs> KeyPressed;

    public ChildForm()
    {
        InitializeComponent();
    }

    private void Child1_KeyUp(object sender, KeyEventArgs e)
    {
        KeyPressed?.Invoke(sender, e);
    }
}
公共部分类子窗体:窗体
{
按下公共事件处理程序键;
公共子表单()
{
初始化组件();
}
私有void Child1\u KeyUp(对象发送方,KeyEventArgs e)
{
按键?.Invoke(发送方,e);
}
}

多亏了Troy Mac1ure的指导。这是一个解决方案,让我可以使用主菜单中的快捷键

ownedForm.KeyPreview = true;
ownedForm.KeyDown += OwnedForm_KeyDown;

private void OwnedForm_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Control)
    {
        foreach (ToolStripMenuItem menuItem in menu.Items)
        {
            foreach (ToolStripMenuItem item in menuItem.DropDownItems.OfType<ToolStripMenuItem>())
            {
                if (item.ShortcutKeys == e.KeyData)
                {
                    item.PerformClick();
                    return;
                }
            }
        }
    }
}
ownedForm.KeyPreview=true;
ownedForm.KeyDown+=ownedForm\u KeyDown;
私有void OwnedForm_KeyDown(对象发送方,KeyEventArgs e)
{
如果(如控制)
{
foreach(菜单项中的ToolStripMenuItem菜单项)
{
foreach(menuItem.DropDownItems.OfType()中的ToolStripMenuItem项)
{
if(item.ShortcutKeys==e.KeyData)
{
item.PerformClick();
回来
}
}
}
}
}

这不处理Alt菜单激活,但Paint.NET也不处理,因此我认为这是一个很好的选择。

两种主要方法。您可以为父窗体订阅的每个子窗体编写一个键事件处理程序(最简单),也可以使用API调用创建一个键捕获。如果您可以完全控制子窗体,我建议使用第一种方法。@TroyMac1ure在该关键事件处理程序中执行什么操作?覆盖,将
WS\u EX\u NOACTIVATE
添加到参数
ExStyle
:并将
WS\u child
添加到标准
样式
:。添加
WS_EX_TOOLWINDOW
,可以让它显得过火,以明确它不是标准表单。表单不会被激活,也不会窃取焦点(即使在单击/选择时)。@Jimi:这是可行的,但代价是要求拥有的表单保留在主表单上。有没有一种方法可以让主窗体响应菜单可能执行的任何操作,同时仍然让所拥有的窗体离开主窗体?如果你在一个工具窗口上,想想Paint.NET是如何工作的。这或多或少是一样的。您只需设置
this.TopMost=true。即使它是一个孩子,它也会在窗体上悬停。唯一的问题是您需要处理ToolWindow标题。如果你点击它,表单仍然被激活(窃取焦点)。有不同的方法来克服这一点。简单的方法是隐藏Toowindow标题并构建一个假标题,然后使用该标题拖动表单。另一个是处理所有的
NC
命中测试。另一个是实现
IMessageFilter
,并将加速器发送/封送给家长;这给了我足够的方向去我需要的地方。