一个简单的基于XML的模块集成框架(含SourceCode)

1. 准备一个xml文件

xmlmenu

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方式来增加模块,感觉不是很方便。
posted @ 2006-04-11 16:58  释子  阅读(2347)  评论(55编辑  收藏  举报