Reputation: 5542
How can I programmatically get a list of shortcut keys that are used in my app? I have a winform with many menus and menu items (including dynamically generated menu items) having assigned shortcut keys.
Really having a hard time keeping track of all the shortcut keys and thought it would be nice to display a list to the user.
Upvotes: 0
Views: 526
Reputation: 30502
I see several problems in your requirement:
File-New
you have to type <alt-F> <alt-N>
; for Edit-Names
you need to type <Alt-E> <Alt-N>
<Alt-N>
is not enough in your shortcut collection, You need the full combination: <alt-F> <alt-N>
for menu File-New, and <Alt-E> <Alt-N>
for Edit-Names<alt-F>
in the file part and the <alt-E>
in the edit part? Then you would have two <alt-N>
shortcuts!<Ctrl-C>
and <Ctrl-V>
?Let's assume your shortcuts are unique, you only want shortcuts for menu items and you want them from the root menu. Alas, class System.Windows.Forms.Shortcut
doesn't have values for <Alt-..>
shortcuts, so we'll just remember the shortcuts as uppercase characters: so "FN" means <alt-F> <alt-N>"
You need to iterate each menu item with all sub-menu items, and check if the Text
property contains an ampersand.
I'll do this as extension methods for MenuStrip
and ToolStripItem
. A menu strip has the main menu's as ToolStripItems in property Items
; a ToolStripItem has the sub menu's in property DropDownItems
.
If you are not familiar with extension methods see extension methods demystified
First the class to put the results:
using System.Windows.Forms;
class ShortCut
{
public string ShortcutSequence {get; set;} = String.Empty;
ToolStripItem ToolStripItem {get; set;}
}
Get the ShortCut of a ToolStripMenuItem or Default if it has no shortcut:
public static char GetShortcutCharOrDefault(this ToolStripMenuItem menuItem)
{
// Return the character after the ampersand in property Text,
// or null if there is no such thing
return menuItem?.Text?.SkipWhile(c => c != '&') // skip until &
.Skip(1) // skip the &
.Select(c => char.ToUpper(c)) // make the char uppercase
.FirstOrDefault() // char after the ampersand
?? default(char); // or default char if no text
}
From a sequence of ToolStripMenuItems to a sequence of Shortcuts.
public static IEnumerable<Shortcut> ToShortcuts(
this IEnumerable<ToolStripMenuItem> menuItems,
string parentShortcutSequence)
{
// TODO: handle invalid input
foreach (var menuItem in menuItems)
{
char shortcutCar = menuItem.GetShortcutChar();
if (shortCutChar != default(char))
{
// This menuItem has a shortcut.
var shortcut = new ShortCut
{
ShortcutSequence = parentShortcutSequence + shortcutChar,
ToolstripItem = menuItem,
}
// return this shortcut
yield return shortcut;
// and check for the shortcuts of the sub menu items
// recursively!
var subShortcuts = menuItem.Items.ToShortcuts(shortcut.ShortcutSequence);
foreach (var subShortcut in subShortcuts)
{
yield return subShortCut);
}
}
}
}
Usage:
MenuStrip mainMenuStrip = ...
IEnumerable<ToolStripItem> menus = mainMenuStrip.Items.Cast<ToolStripItem>();
IEnumerable<Shortcut> shortcuts = menus.ToShortCusts(String.Empty);
Upvotes: 1