自定义菜单快捷键






4.90/5 (10投票s)
允许用户自定义菜单项的快捷键的示例。
引言
此示例代码允许用户自定义分配给菜单项的快捷键。快捷键存储在 user.confg 文件中。因此,该应用程序可以在多用户环境中使用。
当应用程序启动时,会创建一个包含所有菜单项的列表。此列表绑定到一个列表框,用户可以在其中选择一个菜单项。选择后,可以分配或修改该菜单项的快捷键。关闭应用程序时,分配的快捷键会存储在 user.config 文件中。重新启动时,会从 user.config 文件读取这些快捷键并分配给菜单。
背景
快捷键是用于快捷键的键的按位组合。因此,可以通过使用 OR 来组合键以创建快捷键。要获取用于快捷键的键,请使用 XOR 来消除已知键,从而构建快捷键。
要永久保存快捷键,请使用 VS 提供的设置。为了绑定设置(快捷键列表),使用了 ArrayList
。在应用程序的消息循环完成后保存设置。这是因为应用程序中可能还有其他窗体,因此“内存中”的设置只需写入永久存储一次。
所有菜单项的列表
获取所有菜单项的列表
使用递归方法将所有菜单项填充到窗体的列表中。递归通过检查菜单项是否具有下拉菜单项(即,是否是其他菜单项的父项)来实现。
private List<ToolStripMenuItem> menuItemsList = new List<ToolStripMenuItem>();
private void FillListWithMenuEntries(ToolStripItemCollection items)
{
foreach (ToolStripMenuItem item in items)
{
menuItemsList.Add(item);
// Verify if this item is a parent for other menu-items.
// If so add these children by recursion:
if (item.HasDropDownItems)
FillListWithMenuEntries(item.DropDownItems);
}
}
将菜单项列表绑定到列表框
使用 ListBox
的 DataSource
属性来绑定菜单项列表。要显示菜单项的标题,请将 DisplayMember
属性分配给该属性的名称。
lstMenuItems.DataSource = menuItemsList;
lstMenuItems.DisplayMember = "Text";
提供键列表的类
内置的 Keys
枚举顺序不合适,因此我实现了自己的键列表。此列表提供了可能的字母 A-Z 和 F 键(F1-F11)。要将通过名称给定的键转换为 Keys
枚举的值,将使用 KeysConverter
类的一个实例。
/// <summary>
/// Class for use in the List of Keys
/// </summary>
public class Key
{
/// <summary>
/// Name of the Key
/// </summary>
public string Name { get; set; }
/// <summary>
/// KeyCode of the key. ReadOnly.
/// </summary>
public Keys KeyCode
{
get
{
KeysConverter keyConverter = new KeysConverter();
return (Keys)keyConverter.ConvertFrom(this.Name);
}
}
}
为了提供列表,我实现了另一个类。这个类有一个 List
作为其属性。在构造函数中,构建列表。
/// <summary>
/// Class providing a list with Keys for selection
/// </summary>
public class KeysList
{
#region Properties
/// <summary>
/// ReadOnly by private set (for automatic properties in .net 3.5)
/// </summary>
public List<Key> KeyList { get; private set; }
#endregion
//---------------------------------------------------------------------
#region Contructor
/// <summary>
/// Initializes the KeyList with the selectable keys for the
/// shortcuts (A-Z, F1-F11)
/// </summary>
public KeysList()
{
this.KeyList = new List<Key>();
// Letters A-Z:
for (byte b = 65; b <= 90; b++)
{
// Convert ASCII to character:
char c = Convert.ToChar(b);
// Add to list:
this.KeyList.Add(new Key { Name = c.ToString() });
}
// Add F-keys (F1-F11):
for (byte b = 1; b <= 11; b++)
this.KeyList.Add(new Key { Name = "F" + b.ToString() });
}
#endregion
}
字母 A-Z 由 ASCII 码 65-90 表示。通过 Convert.ToChar(ASCII code)
,可以获得字母。
此列表绑定到一个组合框供用户选择。
cmbKeys.DataSource = new KeysList().KeyList;
cmbKeys.DisplayMember = "Name";
cmbKeys.ValueMember = "KeyCode";
组合快捷键
如上所述:快捷键是修饰键和普通键的按位组合。修饰键通过选中(或取消选中)复选框来选择。组合是通过 OR 运算完成的。
Keys shortCut = (Keys)cmbKeys.SelectedValue;
if (chkCtrl.Checked) shortCut |= Keys.Control;
if (chkAlt.Checked) shortCut |= Keys.Alt;
if (chkShift.Checked) shortCut |= Keys.Shift;
根据布尔代数的规则,组合的顺序无关紧要。
为了查询此选定/组合的快捷键是否已分配,我使用 LINQ 查询了所有菜单项的列表。
var query = menuItemsList.FirstOrDefault(s => s.ShortcutKeys == shortCut);
通过使用 FirstOrDefault
,如果查询未获得任何元素,结果将是 null
- 这意味着该快捷键是“空闲”的。
检索用于快捷键的键和修饰键
反向操作:获取组合成快捷键的键和修饰键。
要获取修饰键,我们可以通过按位掩码(AND)来检查快捷键,并查看结果是否等于一个可能的修饰键。在此操作中,设置了复选框的值。
Keys shortCut = selectedItem.ShortcutKeys;
chkCtrl.Checked = (shortCut & Keys.Control) == Keys.Control;
chkAlt.Checked = (shortCut & Keys.Alt) == Keys.Alt;
chkShift.Checked = (shortCut & Keys.Shift) == Keys.Shift;
要获取字母或 F 键,我们必须消除修饰键。这通过组合所有设置的修饰键,然后使用 XOR 从快捷键中移除它们来完成。
示例(使用的值仅为演示工作原理的占位符)
Ctrl = 00100000
Alt = 01000000 OR
-------------------
modifyer = 01100000
shortcut = 01100010
modifyer = 01100000 XOR
-------------------
Key = 00000010
代码
Keys modifiers = Keys.None;
if (chkCtrl.Checked) modifiers |= Keys.Control;
if (chkAlt.Checked) modifiers |= Keys.Alt;
if (chkShift.Checked) modifiers |= Keys.Shift;
Keys buchstabe = shortCut ^ modifiers;
保存快捷键
这是通过使用 VS 内置的 Settings 设计器完成的。在可能的类型中,设计器提供了一个数组列表供选择。在 FormClosing
事件中,必须为该数组列表分配值。仅分配快捷键的值——匹配的菜单项由菜单项列表保留。在 WinForms 应用程序的消息循环完成后,设置将被写入永久存储,因为可能还有其他窗体,并且此操作必须只执行一次。
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// For saving the shortcut in user.config they have to be
// written in an ArrayList. Only the shortcuts are saved:
ArrayList arrList = new ArrayList(menuItemsList.Count);
foreach (ToolStripMenuItem item in menuItemsList)
arrList.Add(item.ShortcutKeys);
Properties.Settings.Default.ShortCuts = arrList;
}
在 Program.cs 中
Application.Run(new Form1());
// Save the settings:
Properties.Settings.Default.Save();
启动时
通过保存设置,值将被写入 user.config 文件。在启动时,必须将这些值分配给菜单项。这是通过创建菜单项列表,然后分配快捷键的值来完成的。
// Get ShortCuts from the saved user-settings (user.config):
ArrayList arrList = Properties.Settings.Default.ShortCuts;
if (arrList != null)
for (int i = 0; i < menuItemsList.Count; i++)
menuItemsList[i].ShortcutKeys = (Keys)arrList[i];
一般来说:ToolStripMenuItem
是一个引用类型。因此,更改任何持有“引用”的变量中的属性会更改“基本”ToolStripMenuItem
中的属性。
使用代码
该示例是一个完整的可运行项目。在您的应用程序中使用时,您需要根据您的用户界面调整代码。有关详细信息,请参阅代码中的注释。
关注点
使用 OR 和 XOR 的按位操作来组合和检索快捷键所使用的键。
另请参阅
用于自定义菜单快捷键的组件 描述了一个允许自定义菜单快捷键的组件。这对于无障碍应用程序可能很有用。
历史
这是第一个版本。灵感来自于论坛上的一个请求。代码是从零开始编写的。未来可能会有一些改进。