Click here to Skip to main content
15,897,334 members
Articles / Desktop Programming / Windows Forms

Component for Customizing Menu Shortcuts

Rate me:
Please Sign up or sign in to vote.
5.00/5 (11 votes)
21 Oct 2008CPOL3 min read 46.3K   1.1K   36  
A component that allows the customization of menu shortcuts. This can be useful for barrier free applications.
#define RECURSION
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace gfoidl.Tools.CustomizeMenuShortCuts
{
	/// <summary>
	/// Component for allowing the customization of menu shortcuts.
	/// <para>
	/// To use the component drag it onto a form, where you want to 
	/// allow the user to customize the menu shortcuts.
	/// </para>
	/// <para>
	/// The component is simple but powerful to use. It provides two
	/// methods:
	/// <list type="bullet">
	///		<item>
	///			<description>
	///				<see cref="CustomizeShortCuts" />
	///			</description>
	///		</item>
	///		<item>
	///			<description>
	///				<see cref="LoadCustomShortCuts" />
	///			</description>
	///		</item>
	/// </list>
	/// </para>
	/// </summary>
	[ToolboxBitmap(typeof(CustomizeMenuShortCuts))]
	[Description("Allows the user to customize menu shortcuts")]
	public sealed class CustomizeMenuShortCuts : Component
	{
		/// <summary>
		/// Shows a form that allows for customization of menu
		/// shortcuts
		/// </summary>
		/// <param name="menuStrip">
		/// The main menu strip of the form
		/// </param>
		/// <example>
		/// This example shows how to load the shortcust from the
		/// user.config
		/// <code>
		/// private void Form1_Load(object sender, System.EventArgs e)
		/// {
		///		customizeMenuShortCuts1.LoadCustomShortCuts(menuStrip1);
		///	}
		///	</code>
		/// </example>
		public void CustomizeShortCuts(MenuStrip menuStrip)
		{
			// Show form that allows for customization:
			frmMain frmMain = new frmMain(menuStrip);
			frmMain.ShowDialog();

			// No we will persist the shortcuts of the menuStrip:
			List<ToolStripItem> menuList = MenuToList(menuStrip.Items);
			Properties.Settings.Default.UserConfigEntries =
				new List<UserConfigEntry>(menuList.Count);

			// Iterate over all menu-items
			foreach (ToolStripItem item in menuList)
			{
				ToolStripMenuItem menuItem = item as ToolStripMenuItem;

				// Separators, for instance, won't be a ToolStripMenuItem
				// so check if it isn't null:
				if (menuItem == null) break;

				Properties.Settings.Default.UserConfigEntries.Add(
					new UserConfigEntry
					{
						Text = menuItem.Text,
						ShortCut = menuItem.ShortcutKeys
					});
			}

			// The settings from a classlibrary have to be saved here,
			// otherwise they will be lost:
			Properties.Settings.Default.Save();
		}
		//---------------------------------------------------------------------
		/// <summary>
		/// Assigns the shortcuts from user.config to the menustrip
		/// </summary>
		/// <param name="menuStrip">
		/// The main menu strip of the form
		/// </param>
		/// <example>
		/// This example demonstrates how simple it is to allow the
		/// user the customization.
		/// <code>
		/// private void button1_Click(object sender, System.EventArgs e)
		/// {
		///		customizeMenuShortCuts1.CustomizeShortCuts(menuStrip1);
		///	}
		///	</code>
		/// </example>
		public void LoadCustomShortCuts(MenuStrip menuStrip)
		{
			// Get the list from the user.config:
			List<UserConfigEntry> userList =
				Properties.Settings.Default.UserConfigEntries;

			if (userList.Count == 0) return;

			// Create a list of the menu-items:
			List<ToolStripItem> menuList = MenuToList(menuStrip.Items);

			// Assign the shortcuts from the user.config to the menulist.
			// It can't be assumed that the list from the user.config has
			// the same length as the list from the menu-items, because
			// there might be changes in the menuStrip (due to updates, etc.)
			// Therefore the list from the menu-items gets iterated and
			// for each item the proper item in the list from the 
			// user.config is searched (the variant with the loops is the
			// fastest in comparison with LINQ and binary search).
			foreach (ToolStripItem menuEntry in menuList)
			{
				ToolStripMenuItem menuItem = menuEntry as ToolStripMenuItem;
				if (menuItem == null) break;
				
				// Search:
				foreach (UserConfigEntry userEntry in userList)
					if (userEntry.Text == menuItem.Text)
					{
						// Found -> assign shortcur:
						menuItem.ShortcutKeys = userEntry.ShortCut;

						break;
					}
			}
		}
		//---------------------------------------------------------------------
		/// <summary>
		/// Creates a (flat) list of the menu structure
		/// </summary>
		/// <param name="items">
		/// Items of the menuStrip
		/// </param>
		/// <returns>
		/// Die flache Liste der Menüstrktur
		/// List with all menu-items
		/// </returns>
		private List<ToolStripItem> MenuToList(ToolStripItemCollection items)
		{
			List<ToolStripItem> list = new List<ToolStripItem>();
#if RECURSION

			// Run throug all items:
		    foreach (ToolStripItem item in items)
		    {
				ToolStripMenuItem menuItem = item as ToolStripMenuItem;

				// Check if it's a ToolStripMenuItem (i.e. no seperator):
				if (menuItem != null)
				{
					// Add to list:
					list.Add(menuItem);

					// Recursion needed?
					if (menuItem.HasDropDownItems)
						list.AddRange(MenuToList(menuItem.DropDownItems));
				}
		    }
#else
			Stack<ToolStripItem> stack = new Stack<ToolStripItem>();
			foreach (ToolStripItem item in items)
				stack.Push(item);

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

				if (menuItem != null)
				{
					list.Add(menuItem);

					if (menuItem.HasDropDownItems)
						foreach (ToolStripItem item in menuItem.DropDownItems)
							stack.Push(item);
				}
			}
#endif

			return list;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Foidl Günther
Austria Austria
Engineer in combustion engine development.
Programming languages: C#, FORTRAN 95, Matlab

FIS-overall worldcup winner in Speedski (Downhill) 2008/09 and 2009/10.

Comments and Discussions