1. 准備一個XML文件
XMLmenu
1<Menu>
2 <MenuItem Name="系統管理" AssemblyName="" FormTag="FALSE" AddToolbar="FALSE">
3 <MenuItem Name="權限管理" ShortCut="" Image="" AssemblyName="" FormTag="FALSE" AddToolButton="FALSE">
4 <MenuItem Name="系統權限管理" ShortCut="" Image="passWord.png" AssemblyName="HustCAD.IntePLM.WinUI.FrmSysRight,IntePLM.TyRightWinUI" FormTag="TRUE" AddToolButton="FALSE"/>
5 <MenuItem Name="權限規則定義" ShortCut="" Image="right.png" AssemblyName="HustCAD.IntePLM.WinUI.FrmRightRule,IntePLM.TyRightWinUI" FormTag="TRUE" AddToolButton="FALSE"/>
6 <MenuItem Name="權限日志" ShortCut="" Image="doc_yellow_edit.png" AssemblyName="HustCAD.IntePLM.WinUI.FrmRightLog,IntePLM.TyRightWinUI" FormTag="TRUE" AddToolButton="FALSE"/>
7 </MenuItem>
8</Menu>
2.准備一個xml schemal文件來驗證XML文件
<?XML version="1.0" encoding="UTF-8"?>
<!-- edited with XMLSpy v2006 sp2 U (http://www.altova.com) by peter (hust) -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualifIEd">
<xs:element name="Menu">
<xs:complexType>
<xs:sequence>
<xs:element ref="MenuItem" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="MenuItem">
<xs:complexType>
<xs:sequence>
<xs:element ref="MenuItem" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="AddToolButton">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="TRUE"/>
<xs:enumeration value="FALSE"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="AddToolbar">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="TRUE"/>
<xs:enumeration value="FALSE"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="AssemblyName" type="xs:string" use="required"/>
<xs:attribute name="FormTag" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="TRUE"/>
<xs:enumeration value="FALSE"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="Image" type="xs:string"/>
<xs:attribute name="Name" type="xs:string" use="required"/>
<xs:attribute name="ShortCut" use="optional">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="F1"/>
<xs:enumeration value="F2"/>
<xs:enumeration value="F3"/>
<xs:enumeration value="F4"/>
<xs:enumeration value="F5"/>
<xs:enumeration value="F6"/>
<xs:enumeration value="F7"/>
<xs:enumeration value="F8"/>
<xs:enumeration value="F9"/>
<xs:enumeration value="F10"/>
<xs:enumeration value="F11"/>
<xs:enumeration value="F12"/>
<xs:enumeration value="Alt0"/>
<xs:enumeration value="Alt1"/>
<xs:enumeration value="Alt2"/>
<xs:enumeration value="Alt3"/>
<xs:enumeration value="Alt4"/>
<xs:enumeration value="Alt5"/>
<xs:enumeration value="Alt6"/>
; <xs:enumeration value="Alt7"/>
<xs:enumeration value="Alt8"/>
<xs:enumeration value="Alt9"/>
<xs:enumeration value="AltBksp"/>
<xs:enumeration value="AltF1"/>
<xs:enumeration value="AltF2"/>
<xs:enumeration value="AltF3"/>
<xs:enumeration value="AltF4"/>
<xs:enumeration value="AltF5"/>
<xs:enumeration value="AltF6"/>
<xs:enumeration value="AltF7"/>
<xs:enumeration value="AltF8"/>
<xs:enumeration value="AltF9"/>
<xs:enumeration value="AltF10"/>
<xs:enumeration value="AltF11"/>
<xs:enumeration value="AltF12"/>
<xs:enumeration value="AltDownArrow"/>
<xs:enumeration value="AltUpArrow"/>
<xs:enumeration value="AltLeftArrow"/>
<xs:enumeration value="AltRightArrow"/>
<xs:enumeration value="Ctrl0"/>
<xs:enumeration value="Ctrl1"/>
<xs:enumeration value="Ctrl2"/>
<xs:enumeration value="Ctrl3"/>
<xs:enumeration value="Ctrl4"/>
<xs:enumeration value="Ctrl5"/>
<xs:enumeration value="Ctrl6"/>
<xs:enumeration value="Ctrl7"/>
<xs:enumeration value="Ctrl8"/>
<xs:enumeration value="Ctrl9"/>
<xs:enumeration value="CtrlA"/>
<xs:enumeration value="CtrlB"/>
<xs:enumeration value="CtrlC"/>
<xs:enumeration value="CtrlD"/>
<xs:enumeration value="CtrlE"/>
<xs:enumeration value="CtrlF"/>
<xs:enumeration value="CtrlG"/>
<xs:enumeration value="CtrlH"/>
<xs:enumeration value="CtrlI"/>
<xs:enumeration value="CtrlJ"/>
<xs:enumeration value="CtrlK"/>
<xs:enumeration value="CtrlL"/>
<xs:enumeration value="CtrlM"/>
<xs:enumeration value="CtrlN"/>
<xs:enumeration value="CtrlO"/>
<xs:enumeration value="CtrlP"/>
<xs:enumeration value="CtrlQ"/>
<xs:enumeration value="CtrlR"/>
<xs:enumeration value="CtrlS"/>
<xs:enumeration value="CtrlT"/>
<xs:enumeration value="CtrlU"/>
<xs:enumeration value="CtrlV"/>
<xs:enumeration value="CtrlX"/>
<xs:enumeration value="CtrlY"/>
<xs:enumeration value="CtrlZ"/>
<xs:enumeration value="CtrlF1"/>
<xs:enumeration value="CtrlF2"/>
<xs:enumeration value="CtrlF3"/>
<xs:enumeration value="CtrlF4"/>
<xs:enumeration value="CtrlF5"/>
<xs:enumeration value="CtrlF6"/>
<xs:enumeration value="CtrlF7"/>
<xs:enumeration value="CtrlF8"/>
<xs:enumeration value="CtrlF9"/>
<xs:enumeration value="CtrlF10"/>
<xs:enumeration value="CtrlF11"/>
<xs:enumeration value="CtrlF12"/>
<xs:enumeration value="CtrlIns"/>
<xs:enumeration value="CtrlShift0"/>
<xs:enumeration value="CtrlShift1"/>
<xs:enumeration value="CtrlShift2"/>
<xs:enumeration value="CtrlShift3"/>
<xs:enumeration value="CtrlShift4"/>
<xs:enumeration value="CtrlShift5"/>
<xs:enumeration value="CtrlShift6"/>
<xs:enumeration value="CtrlShift7"/>
<xs:enumeration value="CtrlShift8"/>
<xs:enumeration value="CtrlShift9"/>
<xs:enumeration value="CtrlShiftA"/>
<xs:enumeration value="CtrlShiftB"/>
<xs:enumeration value="CtrlShiftC"/>
<xs:enumeration value="CtrlShiftD"/>
<xs:enumeration value="CtrlShiftE"/>
<xs:enumeration value="CtrlShiftF"/>
<xs:enumeration value="CtrlShiftG"/>
<xs:enumeration value="CtrlShiftH"/>
<xs:enumeration value="CtrlShiftI"/>
<xs:enumeration value="CtrlShiftJ"/>
<xs:enumeration value="CtrlShiftK"/>
<xs:enumeration value="CtrlShiftL"/>
<xs:enumeration value="CtrlShiftM"/>
<xs:enumeration value="CtrlShiftN"/>
<xs:enumeration value="CtrlShiftO"/>
<xs:enumeration value="CtrlShiFTP"/>
<xs:enumeration value="CtrlShiftQ"/>
<xs:enumeration value="CtrlShiftR"/>
<xs:enumeration value="CtrlShiftS"/>
<xs:enumeration value="CtrlShiftT"/>
<xs:enumeration value="CtrlShiftU"/>
<xs:enumeration value="CtrlShiftV"/>
<xs:enumeration value="CtrlShiftW"/>
<xs:enumeration value="CtrlShiftX"/>
<xs:enumeration value="CtrlShiftY"/>
<xs:enumeration value="CtrlShiftZ"/>
<xs:enumeration value="ShiftIns"/>
<xs:enumeration value="ShiftF1"/>
<xs:enumeration value="ShiftF2"/>
<xs:enumeration value="ShiftF3"/>
<xs:enumeration value="ShiftF4"/>
<xs:enumeration value="ShiftF5"/>
<xs:enumeration value="ShiftF6"/>
<xs:enumeration value="ShiftF7"/>
<xs:enumeration value="ShiftF8"/>
<xs:enumeration value="ShiftF9"/>
<xs:enumeration value="ShiftF10"/>
<xs:enumeration value="ShiftF11"/>
<xs:enumeration value="ShiftF12"/>
<xs:enumeration value=""/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
3。定義一個類來加載菜單
public class MenuLoad
{
private PluginCollection m_plugins = null;
public MenuBar _menbar = new MenuBar();
public ToolStrip _toolbar = new ToolStrip();
private OutlookBar bar = new OutlookBar();
private ImageList imglist = new ImageList();
private StringBuilder builder = new StringBuilder();
public MenuLoad()
{
bar = _menbar.outlookBar;
}
private TabControl tabCtrl;
public TabControl TabCtrl
{
set
{
tabCtrl = value;
}
}
private void ValidationEventHandler(object sender, ValidationEventArgs e)
{
builder.AppendLine("驗證XML文檔的時候發生錯誤:");
builder.AppendLine("嚴重級別:" + e.Severity);
builder.AppendLine("錯誤信息:" + e.Message);
builder.AppendLine("------+--------+-------+------+--------+-------+------+--------+-------+");
builder.AppendLine();
}
/**//// <summary>
/// 驗證XML文件是否是合乎規范的文件
/// </summary>
/// <param name="XMLfile">文件名稱</param>
/// <returns>是則返回true,否則返回false</returns>
private bool ValidateXml(string XMLfile)
{
bool validXML = false;
string spath = "";
spath = Application.StartupPath + "\\configurations\\XMLSMenu.xsd";
if(!System.IO.File.Exists(spath))
{
throw new System.IO.FileNotFoundException(String.Format(Resources.StringFileNotFound, spath));
}
XmlReaderSettings settings = new XMLReaderSettings();
XmlSchemaSet schemaSet = new XMLSchemaSet();
schemaSet.Add(null, spath);
settings.Schemas.Add(schemaSet);
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += new ValidationEventHandler(ValidationEventHandler);
settings.ValidationFlags = settings.ValidationFlags | XMLSchemaValidationFlags.ReportValidationWarnings;
XmlReader reader = XmlReader.Create(XMLfile, settings);
while(reader.Read())
{
}
if(builder.Length > 0)
{
validXML = false;
}
else
{
validXML = true;
}
reader.Close();
return validXML;
}
/**//// <summary>
/// 加載菜單
/// </summary>
/// <param name="main">主菜單</param>
/// <param name="XMLfile">菜單定義文件</param>
public MainMenu LoadMenus(string XMLfile)
{
MainMenu mainmenu = new MainMenu();
try
{
using(new WaitCursor())
{
//驗證XML是否是合乎規范的XML文件
if(ValidateXml(XMLfile))
{
XmlDocument document = new XMLDocument();
document.Load(XMLfile);
XMLNode rootNode = document.DocumentElement;
mainmenu = GetMenus(rootNode);
}
else
{
throw new Exception(builder.ToString());
}
}
}
catch (System.IO.FileNotFoundException)
{
Utility.ShowErrorMsg(String.Format(Resources.StringFileNotFound, XMLfile));
}
return mainmenu;
}
/**//// <summary>
/// 加載菜單
/// </summary>
/// <param name="main">主菜單</param>
/// <param name="node">菜單項節點</param>
private MainMenu GetMenus(XMLNode node)
{
MainMenu mainmenu = new MainMenu();
List<XmlNode> nodelist= new List<XMLNode>();
List<OfficeMenuItem> mnulist = new List<OfficeMenuItem>();
List<IconPanel> iplist = new List<IconPanel>();
string menutext ="";
//首先加載主菜單,避免迭代的時候菜單顯示的過分延遲。
foreach(XMLNode child in node.ChildNodes)
{
if(child.NodeType == XMLNodeType.Element && child.Name == "MenuItem")
{
menutext = child.Attributes["Name"].Value;
OfficeMenuItem item = new OfficeMenuItem(true,menutext);
mainmenu.MenuItems.Add(item);
IconPanel cp = new IconPanel();
bar.AddBand(menutext, cp);
nodelist.Add(child);
mnulist.Add(item);
iplist.Add(cp);
}
}
//加載所有的子菜單
GetSubMenus(iplist.ToArray(),mnulist.ToArray(), nodelist.ToArray());
return mainmenu;
}
/**//// <summary>
/// 加載所有子菜單
/// </summary>
/// <param name="main">主菜單集合</param>
/// <param name="node">菜單節點集合</param>
private void GetSubMenus(IconPanel[] iplist ,OfficeMenuItem[] main, XMLNode[] node)
{
EventHandler handler = new EventHandler(OnPluginClick);
EventHandler handler1 = new EventHandler(OnIconClick);
EventHandler handler2 = new EventHandler(OnButtonClick);
string asmname;
string formtag;
string text;
MenuClass mc;
XMLNode child;
string iconpath = "";
string iconname = "";
string msc = "";
for(int i = 0; i <= main.GetUpperBound(0); i++)
{
//foreach(XMLNode child in node[i].ChildNodes)
for(int j = 0; j < node[i].ChildNodes.Count;j++ )
{
child = node[i].ChildNodes[j];
if(child.NodeType == XMLNodeType.Element && child.Name == "MenuItem")
{
asmname = child.Attributes["AssemblyName"].Value;
formtag = child.Attributes["FormTag"].Value;
text = child.Attributes["Name"].Value;
msc = child.Attributes["ShortCut"].Value;
OfficeMenuItem item = new OfficeMenuItem(true, text, handler);
iconname = child.Attributes["Image"].Value;
if(iconname != string.Empty)
{
iconpath = Themes.GetCurrentThemePath() +iconname;
item.IconPath = iconpath;
}
mc = new MenuClass();
mc.Assemblyname = asmname
mc.FormTag = formtag;
item.Tag = mc;
if(msc != string.Empty)
{
item.Shortcut = MenuShortCut.GetShortCut(msc);
}
main[i].MenuItems.Add(item);
if((iconpath != string.Empty) && System.IO.File.Exists(iconpath))
{ //添加按鈕到OutlookBar
PanelIcon picon = iplist[i].AddIcon(item.Text,Image.FromFile(iconpath),handler1);
picon.Tag = mc;
//添加按鈕到toolbar
ToolStripButton button = new ToolStripButton(item.Text, Image.FromFile(iconpath), handler2);
button.DisplayStyle = ToolStripItemDisplayStyle.Image;
button.ToolTipText = item.Text;
button.Tag = mc;
button.Visible = true;
_toolbar.Items.Add(button);
}
iconpath = "";
mc = null;
if(child.ChildNodes.Count > 0)
{
GetChildMenu(iplist[i],item, child);
}
}
}
//添加分割線
ToolStripSeparator ss = new ToolStripSeparator();
_toolbar.Items.Add(ss);
}
}
/**//// <summary>
/// 加載子菜單
/// </summary>
/// <param name="parent">父菜單</param>
/// <param name="node">父菜單定義XML節點</param>
private void GetChildMenu(IconPanel ip,OfficeMenuItem parent, XMLNode node)
{
EventHandler handler = new EventHandler(OnPluginClick);
EventHandler handler1 = new EventHandler(OnIconClick);
EventHandler handler2 = new EventHandler(OnButtonClick);
MenuClass mc;
string asmname;
string formtag;
string text;
XMLNode child1;
string iconpath = "";
string iconname = "";
string msc = "";
//foreach(XMLNode child1 in node.ChildNodes)
for(int i = 0; i < node.ChildNodes.Count - 1;i++ )
{
child1 = node.ChildNodes[i];
//檢查是否提供了類型
asmname = child1.Attributes["AssemblyName"].Value;
formtag = child1.Attributes["FormTag"].Value;
text = child1.Attributes["Name"].Value;
OfficeMenuItem childitem;
childitem = new OfficeMenuItem(true, text, handler);
childitem.Name = text;
mc = new MenuClass();
mc.Assemblyname = asmname;
mc.FormTag = formtag;
childitem.Tag = mc;
//添加快捷鍵
msc = child1.Attributes["ShortCut"].Value;
if(msc != string.Empty)
{
childitem.Shortcut = MenuShortCut.GetShortCut(msc);
}
//添加圖標
iconname = child1.Attributes["Image"].Value;
if(iconname != string.Empty)
; {
iconpath = Themes.GetCurrentThemePath() + iconname;
childitem.IconPath = iconpath;
}
parent.MenuItems.Add(childitem);
if((iconpath != string.Empty) && System.IO.File.Exists(iconpath))
{ //添加按鈕到OutlookBar
PanelIcon picon = ip.AddIcon(childitem.Text, Image.FromFile(iconpath), handler1);
picon.Tag = mc;
//添加按鈕到toolbar
ToolStripButton button = new ToolStripButton(childitem.Text, Image.FromFile(iconpath), handler2);
button.DisplayStyle = ToolStripItemDisplayStyle.Image;
button.ToolTipText = childitem.Text;
button.Tag = mc;
button.Visible = true;
_toolbar.Items.Add(button);
}
iconpath = "";
mc = null;
if(child1.ChildNodes.Count > 0)
{
GetChildMenu(ip,childitem, child1);
}
}
}
/**//// <summary>
/// 打開一個窗體
/// </summary>
/// <param name="asmname">窗體類程序集和窗體類的組合,從節點的AssemblyName屬性獲取</param>
private void OpenForm(MenuClass mc)
{
string asmname = mc.Assemblyname;
string formtag = mc.FormTag;
if (formtag == "")
{
throw new Exception(Resources.StringNoFormFlag);
}
if(formtag.ToUpper() == "TRUE")
{
if(asmname == string.Empty)
{
throw new NullReferenceException(Resources.StringAssemblyNull);
}
//string[] a = asmname.Split(',');
object obj = null;
Type tp = Type.GetType(asmname);
if(tp != null)
{
obj = Activator.CreateInstance(tp);
}
else
{
throw new Exception("加載程序的時候出錯,請檢查程序(dll,exe)是否存在或者類型是否正確。");
}
//檢查是否是Form類
if((obj == null) | !(obj is Form))
{
throw new Exception(Resources.StringNotForm);
}
Form frm = (obj as Form);
//檢查打開的第一個窗口是否是MDIFORM
if(Application.OpenForms[0].IsMdiContainer)
{
//作為MDICHILDFORM
frm.MdiParent = Application.OpenForms[0];
}
//加載窗體
frm.Show();
}
}
/**//// <summary>
/// 菜單單擊事件
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void OnPluginClick(object sender, EventArgs args)
{
OfficeMenuItem item = (OfficeMenuItem)sender;
MenuClass mc = (MenuClass) item.Tag;
if ((item.Text == "退出") | (item.Text == "EXIT"))
{
OnExitClick(sender, args);
return;
}
OpenForm(mc);
}
}
這裡面用到了delegate,最重要的函數是加載菜單的函數和OnPluginClick函數。
使用這個框架可以動態增加任意的層次的模塊。
微軟的CAB 使用Resigster site方式來增加模塊,感覺不是很方便。
如果您對這個框架感興趣可以郵件 piyanrong@gmail.com。