要用到windows form 的MainMenu控件。于是想做成动态生成并且动态梆定事件,在网上找了一下没有发现什么好的方法。于是自己来研究一下。以前是做web form的东西,对windows form还真有点陌生的感觉。还好以前用Delphi也做过类似人功能有一点印象。就是用递归去创建菜单。好了不多说了,下面看代码。
view sourceprint?001 private void frmMain_Load(object sender, EventArgs e)
002 {
003 CreateMenu();
004 }
005
006 /// <summary>
007 /// 动态创建菜单
008 /// </summary>
009 private void CreateMenu()
010 {
011 //定义一个主菜单
012 MenuStrip mainMenu = new MenuStrip();
013 DataSet ds = new DataSet();
014 //从XML中读取数据。数据结构后面详细讲一下。
015 ds.ReadXml(@"..\..\Menu.xml");
016 DataView dv = ds.Tables[0].DefaultView;
017 //通过DataView来过滤数据首先得到最顶层的菜单
018 dv.RowFilter = "ParentItemID=0";
019 for(int i=0; i<dv.Count;i++)
020 {
021 //创建一个菜单项
022 ToolStripMenuItem topMenu = new ToolStripMenuItem();
023 //给菜单赋Text值。也就是在界面上看到的值。
024 topMenu.Text = dv[i]["Text"].ToString();
025 //如果是有下级菜单则通过CreateSubMenu方法来创建下级菜单
026 if (Convert.ToInt16(dv[i]["IsModule"]) == 1)
027 {
028 //以ref的方式将顶层菜单传递参数,因为他可以在赋值后再回传。--也许还有更好的方法^_^.
029 CreateSubMenu(ref topMenu, Convert.ToInt32(dv[i]["ItemID"]),ds.Tables[0]);
030 }
031 //显示应用程序中已打开的 MDI 子窗体列表的菜单项
032 mainMenu.MdiWindowListItem = topMenu;
033 //将递归附加好的菜单加到菜单根项上。
034 mainMenu.Items.Add(topMenu);
035 }
036 mainMenu.Dock = DockStyle.Top;
037 //将窗体的MainMenuStrip梆定为mainMenu.
038 this.MainMenuStrip = mainMenu;
039 //这句很重要。如果不写这句菜单将不会出现在主窗体中。
040 this.Controls.Add(mainMenu);
041 }
042
043 /// <summary>
044 /// 创建子菜单
045 /// </summary>
046 /// <param name="topMenu">父菜单项</param>
047 /// <param name="ItemID">父菜单的ID</param>
048 /// <param name="dt">所有菜单数据集</param>
049 private void CreateSubMenu(ref ToolStripMenuItem topMenu,int ItemID, DataTable dt)
050 {
051 DataView dv = new DataView(dt);
052 //过滤出当前父菜单下在所有子菜单数据(仅为下一层的)
053 dv.RowFilter = "ParentItemID=" + ItemID.ToString();
054
055 for (int i = 0; i < dv.Count; i++)
056 {
057 //创建子菜单项
058 ToolStripMenuItem subMenu = new ToolStripMenuItem();
059 subMenu.Text = dv[i]["Text"].ToString();
060 //如果还有子菜单则继续递归加载。
061 if (Convert.ToInt16(dv[i]["IsModule"]) == 1)
062 {
063 //递归调用
064 CreateSubMenu(ref subMenu, Convert.ToInt32(dv[i]["ItemID"]), dt);
065 }
066 else
067 {
068 //扩展属性可以加任何想要的值。这里用formName属性来加载窗体。
069 subMenu.Tag = dv[i]["FormName"].ToString();
070 //给没有子菜单的菜单项加事件。
071 subMenu.Click += new EventHandler(subMenu_Click);
072 }
073 if (dv[i]["ImageName"].ToString().Length > 0)
074 {
075 //设置菜单项前面的图票为16X16的图片文件。
076 Image img = Image.FromFile(@"..\..\Image\"+dv[i]["ImageName"].ToString());
077 subMenu.Image = img;
078 subMenu.Image.Tag = dv[i]["ImageName"].ToString();
079 }
080 //将菜单加到顶层菜单下。
081 topMenu.DropDownItems.Add(subMenu);
082 }
083 }
084
085 /// <summary>
086 /// 菜单单击事件
087 /// </summary>
088 /// <param name="sender"></param>
089 /// <param name="e"></param>
090 void subMenu_Click(object sender, EventArgs e)
091 {
092 //tag属性在这里有用到。
093 string formName = ((ToolStripMenuItem)sender).Tag.ToString();
094 CreateFormInstance(formName);
095 }
096
097 /// <summary>
098 /// 创建form实例。
099 /// </summary>
100 /// <param name="formName">form的类名</param>
101 private void CreateFormInstance(string formName)
102 {
103 bool flag = false;
104 //遍历主窗口上的所有子菜单
105 for(int i=0;i<this.MdiChildren.Length; i++)
106 {
107 //如果所点的窗口被打开则重新激活
108 if (this.MdiChildren[i].Tag.ToString().ToLower() == formName.ToLower())
109 {
110 this.MdiChildren[i].Activate();
111 this.MdiChildren[i].Show();
112 this.MdiChildren[i].WindowState = FormWindowState.Normal;
113 flag = true;
114 break;
115 }
116 }
117 if (!flag)
118 {
119 //如果不存在则用反射创建form窗体实例。
120 Assembly asm = Assembly.Load("Fastyou.BookShop.Win");//程序集名
121 object frmObj = asm.CreateInstance("Fastyou.BookShop.Win." + formName);//程序集+form的类名。
122 Form frms = (Form)frmObj;
123 //tag属性要重新写一次,否则在第二次的时候取不到。原因还不清楚。有知道的望告知。
124 frms.Tag = formName.ToString();
125 frms.MdiParent = this;
126 frms.Show();
127 }
128 }
view sourceprint?01 <?xml version="1.0" encoding="utf-8" ?>
02 <Menus>
03 <MenuItem>
04 <Text>资料管理</Text>
05 <ItemID>1000</ItemID>
06 <ParentItemID>0</ParentItemID>
07 <FormName></FormName>
08 <IsModule>1</IsModule>
09 <Level>1</Level>
10 <ImageName>01.bmp</ImageName>
11 </MenuItem>
12 <MenuItem>
13 <Text>产品管理</Text>
14 <ItemID>1100</ItemID>
15 <ParentItemID>0</ParentItemID>
16 <FormName></FormName>
17 <IsModule>1</IsModule>
18 <Level>1</Level>
19 <ImageName>16x16_ico_pdf.gif</ImageName>
20 </MenuItem>
21 <MenuItem>
22 <Text>进书管理</Text>
23 <ItemID>100001</ItemID>
24 <ParentItemID>1000</ParentItemID>
25 <FormName>frmInputBooks</FormName>
26 <IsModule>0</IsModule>
27 <Level>2</Level>
28 <ImageName>crest16x16.gif</ImageName>
29 </MenuItem>
30 <MenuItem>
31 <Text>买卖管理</Text>
32 <ItemID>100002</ItemID>
33 <ParentItemID>1000</ParentItemID>
34 <FormName></FormName>
35 <IsModule>1</IsModule>
36 <Level>2</Level>
37 <ImageName>ico16-16.gif</ImageName>
38 </MenuItem>
39 <MenuItem>
40 <Text>作业管理</Text>
41 <ItemID>110001</ItemID>
42 <ParentItemID>1100</ParentItemID>
43 <FormName></FormName>
44 <IsModule>1</IsModule>
45 <Level>2</Level>
46 <ImageName>ico_info_16x16_mask.gif</ImageName>
47 </MenuItem>
48 <MenuItem>
49 <Text>买书管理</Text>
50 <ItemID>10000201</ItemID>
51 <ParentItemID>100002</ParentItemID>
52 <FormName></FormName>
53 <IsModule>1</IsModule>
54 <Level>3</Level>
55 <ImageName>ico_tmn_16x16.jpg</ImageName>
56 </MenuItem>
57 <MenuItem>
58 <Text>买sss管理</Text>
59 <ItemID>1000020101</ItemID>
60 <ParentItemID>10000201</ParentItemID>
61 <FormName>frmBuyBook</FormName>
62 <IsModule>0</IsModule>
63 <Level>4</Level>
64 <ImageName>ico16-16.gif</ImageName>
65 </MenuItem>
66 <MenuItem>
67 <Text>dsafasdf</Text>
68 <ItemID>11000101</ItemID>
69 <ParentItemID>110001</ParentItemID>
70 <FormName>frmBuyBook</FormName>
71 <IsModule>0</IsModule>
72 <Level>3</Level>
73 <ImageName>ico16-16.gif</ImageName>
74 </MenuItem>
75 </Menus>
下面来说明一下XML文件。
Text:为显示在窗体上的文字,
ItemID:为菜单的ID,
ParentItemID:为此菜单的父菜单ID如果是顶级菜单则为0
FormName:为单击菜单所要显示的窗体类名如果是还有下级菜单的则不要写。
IsModule:是否还有子菜单1有,0没有
Level:菜单所在的层数。目前还没用到。
ImageName:菜单前的图标为16x16的图片文件。
在这里还可以根据自己的需要加其它的属性,也可以写成以数据库的方式。