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