C# 创建动态菜单






3.38/5 (14投票s)
2003年9月6日
2分钟阅读

110670

3947
在 C# 中动态创建菜单。
引言
本文展示了如何在 C# 中以几个简单的步骤动态创建菜单。它还展示了如何使用 MenuItem
的 OwnerDraw
功能。
背景
几个月前,看到我的一些文章后,有人发邮件给我,请求帮助创建菜单项以将最近使用的文件显示到项目中。该请求是针对 VC++ 中的解决方案。由于我对它非常熟悉,所以我给他发送了必要的源代码,但最近当我(暂时)切换到 C# 时,我遇到了同样的问题,并且在 MSDN 帮助中找不到创建此类菜单的任何参考。我确实找到了一些粗略的信息,我对这些信息进行了一些研究,发现它不是很难,但也不是很容易。但是,当我在 .NET 的 Visual Basic 方面尝试相同的技术时,我没有成功(我现在仍在尝试)。
重要
该项目是在 .NET (7.0 - Visual Studio .NET 的第一个版本) 中开发的,该项目使用以下注册表项来检索并在菜单中显示最近的项目。
RegistryKey regKey =
Registry.CurrentUser.OpenSubKey
("Software\\Microsoft\\VisualStudio\\7.0\\ProjectMRUList");
如果您使用的是 Visual Studio .NET 的更高版本,则可能需要修改上述行以反映您的 .NET 版本;可能类似于这样,然后重新构建应用程序。
RegistryKey regKey =
Registry.CurrentUser.OpenSubKey
("Software\\Microsoft\\VisualStudio\\7.1\\ProjectMRUList");
使用代码
我没有花时间为此目的开发单独的类,因为该技术非常简单,而且我个人鼓励开发人员坚持使用“复制/粘贴/修改”的方法。这样,您学习到的东西比添加其他人制作的类更多,在这些类中,您通过传递一些参数来创建菜单,并且一无所获。您还被迫添加作者的版权声明。
由于项目非常小,因此我在本文中包含了一些重要的源代码部分。
public void UpdateMenu()
{
// retreive names of all recent project
// from the system registry
RegistryKey regKey = Registry.CurrentUser.OpenSubKey
("Software\\Microsoft\\VisualStudio\\7.0\\ProjectMRUList");
if (regKey == null)
{
// such key does not exist
return;
}
MenuItem mnu = new MenuItem();
String[] filename = regKey.GetValueNames();
IEnumerator iEnum = filename.GetEnumerator();
// Iterate through all items
while(iEnum.MoveNext())
{
String val = (String)iEnum.Current;
String data = (String)regKey.GetValue(val);
MenuItem mi = AddMenuItem(data);
mnu.MenuItems.Add(mi);
}
menuItemRecentProjects.MergeMenu(mnu);
regKey.Close();
}
添加每个 MenuItem
的函数如下
private MenuItem AddMenuItem(String title)
{
// create a new menuitem
MenuItem mi = new MenuItem(title);
// set as Delegate for the Click Event of this MenuItem
mi.Click += new
System.EventHandler(this.menuItemDynamicMenu_Click);
// Ownerdraw is needed only if you want to
// add Icons and custom highlighting etc
mi.OwnerDraw = true;
// ..._MeasureItem, ..._DrawItem Virtual function are called
// by the system to render the items individually
// every time a visual aspect changes
mi.DrawItem += new
System.Windows.Forms.DrawItemEventHandler
(this.menuItemDynamicMenu_DrawItem );
mi.MeasureItem += new
System.Windows.Forms.MeasureItemEventHandler
(this.menuItemDynamicMenu_MeasureItem);
// ..._DrawItem and ..._MeasureItem EventHandler Delegates
// for each MenuItem are created above
return mi;
}
..._MeasureItem(...)
和 ..._DrawItem(...)
的代码如下所示。请注意,由于 MenuItem
是在运行时动态创建的,因此无法从 Visual Studio IDE 的属性/事件窗口创建以下事件,而必须手动创建。我已将事件命名为 menuItemDynamicMenu_MeasureItem
和 menuItemDynamicMenu_DrawItem
。您可以随意命名它们,但最好附加 _MeasureItem
和 _DrawItem
以便于识别。每个这些事件的参数必须如下。如果您省略 _MeasureItem
事件,则您的菜单大小将为 10x2。
..._MeasureItem(object sender, System.Windows.Forms.MeasureItemEventArgs e)
..._DrawItem(object sender,
private void menuItemDynamicMenu_MeasureItem(object sender,
System.Windows.Forms.MeasureItemEventArgs e)
{
// retreive the MenuItem in question
// note : ..._MeasureItem is called before ..._DrawItem
MenuItem item = (MenuItem)sender;
// we set the height of each item to 20
// remember the icons are 16x16
e.ItemHeight = 20;
SizeF stringSize = new SizeF();
stringSize = e.Graphics.MeasureString(item.Text, this.Font);
// set the width of the item based on the
// length of the prompt
e.ItemWidth = (int)stringSize.Width;
}
_DrawItem(...)
的代码。
private void menuItemDynamicMenu_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e) { // unfortunately only 2 states are passed to this function // NoAccelerator // Selected, NoAccelerator SolidBrush brush; if(e.State.Equals(DrawItemState.Selected | DrawItemState.NoAccelerator )) { // Item is Selected highlight the Item Pen blackPen = new Pen(Color.Black, 1); e.Graphics.DrawRectangle(blackPen, e.Bounds); brush = new SolidBrush(Color.FromArgb(40, 10, 10, 255)); // create a highlight rectangle e.Graphics.FillRectangle(brush, e.Bounds); return; } if(e.State.Equals(DrawItemState.NoAccelerator)) { // Item is not selected, remove highlight rectangle // created above Pen whitePen = new Pen(Color.White, 1); e.Graphics.DrawRectangle(whitePen, e.Bounds) ; SolidBrush brushErase = new SolidBrush(Color.White ); e.Graphics.FillRectangle(brushErase, e.Bounds); MenuItem item = (MenuItem)sender; // get the MenuItem's Rectangle Rectangle rect = e.Bounds; SolidBrush drawBrush = new SolidBrush(Color.Black); RectangleF drawRect = new RectangleF( e.Bounds.X+20, e.Bounds .Y, e.Bounds.Width , e.Bounds .Height); brush = new SolidBrush(Color.FromArgb(236, 233,216)); // draw a transparent rectangle over the Image // else the Image will not be visible e.Graphics.FillRectangle(brush, rect.Left, rect.Top, 18, rect.Bottom); // Draw MenuItem Text , you can use some funcky // Font for this purpose e.Graphics.DrawString(item.Text , e.Font, drawBrush, drawRect ); // Render the Image (Icon) // i have used a ImageList imageList1.Draw(e.Graphics, rect.Left+1, rect.Top ,14,14, 0); } }
历史
- First version.