Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何让子窗口将密钥发送回下方?_C#_Winforms_Keyboard Events - Fatal编程技术网

C# 如何让子窗口将密钥发送回下方?

C# 如何让子窗口将密钥发送回下方?,c#,winforms,keyboard-events,C#,Winforms,Keyboard Events,我几乎肯定遗漏了一些非常明显的东西。我有一个单例主窗体,带有各种快捷菜单项。我有子窗口,可以嵌入主窗体,也可以自己浮动。主窗体类有一个指向现有主窗体的静态成员,因此子窗口可以访问其公共函数。我希望通常链接到工具栏条目的热键能够从子窗口工作,并且我不希望复制代码。我知道我必须在主窗体上调用一个keypress事件,但是我今天运行的是一个完全空白的程序 举一个简单的例子,有一些菜单项可以保存当前文件并将窗口集中在鼠标所处的位置,分别由Ctrl+S和Ctrl+E触发。在我的主窗体中,它们被设置为键盘快

我几乎肯定遗漏了一些非常明显的东西。我有一个单例主窗体,带有各种快捷菜单项。我有子窗口,可以嵌入主窗体,也可以自己浮动。主窗体类有一个指向现有主窗体的静态成员,因此子窗口可以访问其公共函数。我希望通常链接到工具栏条目的热键能够从子窗口工作,并且我不希望复制代码。我知道我必须在主窗体上调用一个keypress事件,但是我今天运行的是一个完全空白的程序


举一个简单的例子,有一些菜单项可以保存当前文件并将窗口集中在鼠标所处的位置,分别由
Ctrl+S
Ctrl+E
触发。在我的主窗体中,它们被设置为键盘快捷键,但对于后一个命令,实际的繁重工作是由我的子窗口完成的。我通过在我的子窗口中捕获一个按键按下事件暂时修复了它,但这意味着同一快捷方式显示在两个不同的位置。

处理按键快捷方式的解决方案似乎很少。 其中之一可能是按照建议安装键盘挂钩。 您也可以尝试通过添加自定义消息过滤器来处理此问题,正如建议的那样,但是,我还没有验证发布在那里的代码


带有钩子的解决方案似乎有点棘手,因此您可能希望首先尝试自定义消息过滤器。

根据我对上面Lukasz M的评论,出于遗留原因,我需要维护当前的菜单结构,即所有工程师都习惯于更改菜单,他们希望菜单快捷方式能够自动工作。我可能会使用自定义消息过滤器修改中心热键位置,为菜单项生成快捷方式文本,但这会增加额外的复杂性,下次有人插手添加快速菜单项时,可能会撤消该操作。因此,我采用了我在评论中提到的解决方案,为子窗口提供了一个不可见的菜单

令我大吃一惊的是,如果菜单的
Visible
属性设置为false,热键就可以正常工作。如果从子窗体调用,则与主窗体中的菜单项相关联的事件可以很好地工作,因为它们是相对于定义它们的窗口执行的,而不是由调用它们的窗口执行的。因此,我的第一个解决方案是从主窗体中获取
MenuStrip
,并将其添加到子窗体中。这不起作用,因为在子窗体中使其不可见会使其在主窗体中也不可见。我的下一个尝试涉及创建一个新的隐藏的
MenuStrip
,并将
ToolStripMenuItem
项从主窗体的
MenuStrip
添加到它上面。这破坏了热键功能,可能是因为菜单项现在存在于多个地方。最后,我创建了菜单项的浅层副本,这些菜单项只包含快捷键、
Tag
属性(对于使用它的一些菜单项是必需的)和事件处理程序(最后一个是通过中描述的方法完成的)。在做了一些修改之后,我意识到我不需要维护菜单的结构,我只需要带有快捷方式的项目。这就是我的结论:

主要形式:

  /// <summary>
  /// Returns copies of all menu shortcut items in the main form.
  /// </summary>
  /// <returns>A list containing copies of all of the menu items with a keyboard shortcut.</returns>
  public static List<ToolStripMenuItem> GetMenuShortcutClones()
  {
     List<ToolStripMenuItem> shortcutItems = new List<ToolStripMenuItem>();

     Stack<ToolStripMenuItem> itemsToBeParsed = new Stack<ToolStripMenuItem>();

     foreach (ToolStripItem menuItem in mainForm.menuStrip.Items)
     {
        if (menuItem is ToolStripMenuItem)
        {
           itemsToBeParsed.Push((ToolStripMenuItem)menuItem);
        }
     }

     while (itemsToBeParsed.Count > 0)
     {
        ToolStripMenuItem menuItem = itemsToBeParsed.Pop();

        foreach (ToolStripItem childItem in menuItem.DropDownItems)
        {
           if (childItem is ToolStripMenuItem)
           {
              itemsToBeParsed.Push((ToolStripMenuItem)childItem);
           }
        }

        if (menuItem.ShortcutKeys != Keys.None)
        {
           shortcutItems.Add(CloneMenuItem(menuItem));
        }
     }

     return shortcutItems;
  }

  /// <summary>
  /// Returns an effective shortcut clone of a ToolStripMenuItem. It does not copy the name
  /// or text, but it does copy the shortcut and the events associated with the menu item.
  /// </summary>
  /// <param name="menuItem">The MenuItem to be cloned</param>
  /// <returns>The newly generated clone.</returns>
  private static ToolStripMenuItem CloneMenuItem(ToolStripMenuItem menuItem)
  {
     ToolStripMenuItem copy = new ToolStripMenuItem();
     copy.ShortcutKeys = menuItem.ShortcutKeys;
     copy.Tag = menuItem.Tag;

     var eventsField = typeof(Component).GetField("events", BindingFlags.NonPublic | BindingFlags.Instance);
     var eventHandlerList = eventsField.GetValue(menuItem);
     eventsField.SetValue(copy, eventHandlerList);

     return copy;
  }
  private void OnRefresh(object sender, EventArgs e)
  {
     // Refresh the hiddenShortcutMenu.
     List<ToolStripMenuItem> shortcutList = MainForm.GetMenuShortcutClones();
     hiddenShortcutMenu.Items.Clear();
     hiddenShortcutMenu.Items.AddRange(shortcutList.ToArray());
  }
//
///返回主窗体中所有菜单快捷方式项的副本。
/// 
///包含所有带有键盘快捷键的菜单项副本的列表。
公共静态列表GetMenuShortcutClones()
{
List shortcutItems=新列表();
Stack itemsToBeParsed=新堆栈();
foreach(mainForm.menuStrip.Items中的ToolStripItem menuItem)
{
如果(menuItem是ToolStripMenuItem)
{
Push((ToolStripMenuItem)menuItem);
}
}
while(itemsToBeParsed.Count>0)
{
ToolStripMenuItem menuItem=itemsToBeParsed.Pop();
foreach(menuItem.DropDownItems中的ToolStripItem childItem)
{
if(子项为ToolStripMenuItem)
{
Push((ToolStripMenuItem)childItem);
}
}
if(menuItem.ShortcutKeys!=key.None)
{
shortcutItems.Add(CloneMenuItem(menuItem));
}
}
返回快捷项;
}
/// 
///返回ToolStripMenuItem的有效快捷方式克隆。它不复制名称
///或文本,但它会复制快捷方式和与菜单项关联的事件。
/// 
///要克隆的菜单项
///新生成的克隆。
专用静态ToolStripMenuItem CloneMenuItem(ToolStripMenuItem menuItem)
{
ToolStripMenuItem copy=新建ToolStripMenuItem();
copy.ShortcutKeys=menuItem.ShortcutKeys;
copy.Tag=menuItem.Tag;
var eventsField=typeof(Component.GetField(“事件”,BindingFlags.NonPublic | BindingFlags.Instance);
var eventHandlerList=eventsField.GetValue(menuItem);
eventsField.SetValue(复制,eventHandlerList);
返回副本;
}
子表单:

  /// <summary>
  /// Returns copies of all menu shortcut items in the main form.
  /// </summary>
  /// <returns>A list containing copies of all of the menu items with a keyboard shortcut.</returns>
  public static List<ToolStripMenuItem> GetMenuShortcutClones()
  {
     List<ToolStripMenuItem> shortcutItems = new List<ToolStripMenuItem>();

     Stack<ToolStripMenuItem> itemsToBeParsed = new Stack<ToolStripMenuItem>();

     foreach (ToolStripItem menuItem in mainForm.menuStrip.Items)
     {
        if (menuItem is ToolStripMenuItem)
        {
           itemsToBeParsed.Push((ToolStripMenuItem)menuItem);
        }
     }

     while (itemsToBeParsed.Count > 0)
     {
        ToolStripMenuItem menuItem = itemsToBeParsed.Pop();

        foreach (ToolStripItem childItem in menuItem.DropDownItems)
        {
           if (childItem is ToolStripMenuItem)
           {
              itemsToBeParsed.Push((ToolStripMenuItem)childItem);
           }
        }

        if (menuItem.ShortcutKeys != Keys.None)
        {
           shortcutItems.Add(CloneMenuItem(menuItem));
        }
     }

     return shortcutItems;
  }

  /// <summary>
  /// Returns an effective shortcut clone of a ToolStripMenuItem. It does not copy the name
  /// or text, but it does copy the shortcut and the events associated with the menu item.
  /// </summary>
  /// <param name="menuItem">The MenuItem to be cloned</param>
  /// <returns>The newly generated clone.</returns>
  private static ToolStripMenuItem CloneMenuItem(ToolStripMenuItem menuItem)
  {
     ToolStripMenuItem copy = new ToolStripMenuItem();
     copy.ShortcutKeys = menuItem.ShortcutKeys;
     copy.Tag = menuItem.Tag;

     var eventsField = typeof(Component).GetField("events", BindingFlags.NonPublic | BindingFlags.Instance);
     var eventHandlerList = eventsField.GetValue(menuItem);
     eventsField.SetValue(copy, eventHandlerList);

     return copy;
  }
  private void OnRefresh(object sender, EventArgs e)
  {
     // Refresh the hiddenShortcutMenu.
     List<ToolStripMenuItem> shortcutList = MainForm.GetMenuShortcutClones();
     hiddenShortcutMenu.Items.Clear();
     hiddenShortcutMenu.Items.AddRange(shortcutList.ToArray());
  }
private void OnRefresh(对象发送方,事件参数e)
{
//刷新HiddenShortcut菜单。
List shortcutList=MainForm.GetMenuShortcutClones();
hiddenShortcutMenu.Items.Clear();
hiddenShortcutMenu.Items.AddRange(shortcutList.ToArray());
}

在子窗体的构造函数中,我实例化了
hiddenShortcutMenu
,将
Visible
设置为false,将其分配给子窗体的控件,并设置事件。最后一个有点麻烦,因为菜单有时会根据上下文而改变,所以我必须定期刷新它。目前,我已将其设置为最大程度的妄想症的
Paint
事件,但我想我将尝试找到一种方法,让主窗体显示它已更改了菜单结构。

我还在探索另一种可能的解决方案。自从