MDI程序中反射生成菜单并与权限控制的结合(利用XML将模块组件装配与卸载)
思路:
第一步:将程序按模块划分,提供一个接口给这些模块,模块要实现这个接口,将模块封装成组件。
第二步:将组件名、组件中的成员以及权限信息一起写入XML文件。
第三步:在主程序中读取XML文件并结合用户权限判断,再用反射生成菜单。
下面是小例子
首先定义一个接口,然后封装组件
在将菜单信息和功能写入XML文件dymenu.xml
在主窗体中考虑权限并用反射创建菜单,这里只是模拟权限控制。
第一步:将程序按模块划分,提供一个接口给这些模块,模块要实现这个接口,将模块封装成组件。
第二步:将组件名、组件中的成员以及权限信息一起写入XML文件。
第三步:在主程序中读取XML文件并结合用户权限判断,再用反射生成菜单。
下面是小例子
首先定义一个接口,然后封装组件
public interface IMdiFunc
{
void void MdiParentToolBarOnClick(string st);
}
{
void void MdiParentToolBarOnClick(string st);
}
在将菜单信息和功能写入XML文件dymenu.xml
<?xml version="1.0" encoding="utf-8" ?>
<ROOT>
<主菜单>主菜单1
<子菜单>打开窗口1</子菜单>
<菜单DLL>MyForms.dll</菜单DLL>
<菜单Func>OpenForm1</菜单Func>
<菜单Right>A</菜单Right>
<子菜单>打开窗口2</子菜单>
<菜单DLL>MyForms.dll</菜单DLL>
<菜单Func>OpenForm2</菜单Func>
<菜单Right>B</菜单Right>
</主菜单>
<主菜单>主菜单2
<子菜单>打开窗口3</子菜单>
<菜单DLL>MyDlls.dll</菜单DLL>
<菜单Func>OpenForm3</菜单Func>
<菜单Right>C</菜单Right>
</主菜单>
</ROOT>
<ROOT>
<主菜单>主菜单1
<子菜单>打开窗口1</子菜单>
<菜单DLL>MyForms.dll</菜单DLL>
<菜单Func>OpenForm1</菜单Func>
<菜单Right>A</菜单Right>
<子菜单>打开窗口2</子菜单>
<菜单DLL>MyForms.dll</菜单DLL>
<菜单Func>OpenForm2</菜单Func>
<菜单Right>B</菜单Right>
</主菜单>
<主菜单>主菜单2
<子菜单>打开窗口3</子菜单>
<菜单DLL>MyDlls.dll</菜单DLL>
<菜单Func>OpenForm3</菜单Func>
<菜单Right>C</菜单Right>
</主菜单>
</ROOT>
在主窗体中考虑权限并用反射创建菜单,这里只是模拟权限控制。
主窗体
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Reflection;
using System.Xml;
using Interface;
namespace DynamicMenus
{
/**//// <summary>
/// MainForm 的摘要说明。
/// </summary>
public class MainForm : System.Windows.Forms.Form
{
private System.Windows.Forms.MainMenu mainMenu1;
//主菜单
private string[] mMenus;
//主菜单状态
private bool[] bMenus;
//子菜单
private string[][] mItems;
//子菜单对应的dll
private string[][] mDlls;
//子菜单对应的函数
private string [][] mFuncs;
private string [][] mRight;
private OfficeMenus.OfficeMenus officeMenus1;
private System.Windows.Forms.ToolBar toolBar1;
private System.Windows.Forms.ToolBarButton tbbAdd;
private System.Windows.Forms.ToolBarButton tbbModify;
private System.Windows.Forms.ToolBarButton tbbDelete;
private System.Windows.Forms.ToolBarButton tbbSave;
private System.Windows.Forms.ToolBarButton tbbExit;
private System.ComponentModel.IContainer components;
public MainForm()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
OrtherInitialize();
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}
/**//// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
Windows 窗体设计器生成的代码#region Windows 窗体设计器生成的代码
/**//// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.officeMenus1 = new OfficeMenus.OfficeMenus(this.components);
this.mainMenu1 = new System.Windows.Forms.MainMenu(this.components);
this.toolBar1 = new System.Windows.Forms.ToolBar();
this.tbbAdd = new System.Windows.Forms.ToolBarButton();
this.tbbModify = new System.Windows.Forms.ToolBarButton();
this.tbbDelete = new System.Windows.Forms.ToolBarButton();
this.tbbSave = new System.Windows.Forms.ToolBarButton();
this.tbbExit = new System.Windows.Forms.ToolBarButton();
this.SuspendLayout();
//
// officeMenus1
//
this.officeMenus1.ImageList = null;
//
// toolBar1
//
this.toolBar1.Buttons.AddRange(new System.Windows.Forms.ToolBarButton[] {
this.tbbAdd,
this.tbbModify,
this.tbbDelete,
this.tbbSave,
this.tbbExit});
this.toolBar1.DropDownArrows = true;
this.toolBar1.Location = new System.Drawing.Point(0, 0);
this.toolBar1.Name = "toolBar1";
this.toolBar1.ShowToolTips = true;
this.toolBar1.Size = new System.Drawing.Size(584, 41);
this.toolBar1.TabIndex = 1;
this.toolBar1.ButtonClick += new System.Windows.Forms.ToolBarButtonClickEventHandler(this.toolBar1_ButtonClick);
//
// tbbAdd
//
this.tbbAdd.Name = "tbbAdd";
this.tbbAdd.Text = "新增";
//
// tbbModify
//
this.tbbModify.Name = "tbbModify";
this.tbbModify.Text = "修改";
//
// tbbDelete
//
this.tbbDelete.Name = "tbbDelete";
this.tbbDelete.Text = "删除";
//
// tbbSave
//
this.tbbSave.Name = "tbbSave";
this.tbbSave.Text = "保存";
//
// tbbExit
//
this.tbbExit.Name = "tbbExit";
this.tbbExit.Text = "退出";
//
// MainForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(584, 341);
this.Controls.Add(this.toolBar1);
this.IsMdiContainer = true;
this.Name = "MainForm";
this.Text = "基于组件装配的企业信息系统";
this.Closed += new System.EventHandler(this.MainForm_Closed);
this.Load += new System.EventHandler(this.MainForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private void OrtherInitialize()
{
//
//动态生成菜单
//
ReadXml(); //从菜单定义文件dymenu.xml中读取数据放入定义菜单的数组中
//从数组中取出菜单定义动态生成菜单
for(int i=0;i<mMenus.Length;i++)
{
if(bMenus[i])
{
MenuItem newDyMainItem = new MenuItem(mMenus[i]);
this.mainMenu1.MenuItems.Add(newDyMainItem);
for(int j=0;j<mItems[i].Length;j++)
{
MenuItem newDyItem = new MenuItem(mItems[i][j]);
newDyMainItem.MenuItems.Add(newDyItem);
//将每个菜单的Click事件指向同一个方法
newDyItem.Click += new System.EventHandler(this.NewClick);
}
}
}//End
//这里可以添加一些固定的菜单(不要定义index值,而且一定要在动态生成菜单的后面加,因为后面Click事件判断是按index的值来确定的)
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {});
this.Menu = mainMenu1;
}
/**//// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new MainForm());
}
使用反射生成菜单事件#region 使用反射生成菜单事件
/**//// <summary>
/// 使用反射生成菜单事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void NewClick(object sender, System.EventArgs e)
{
MenuItem item = (MenuItem)sender;
MenuItem par = (MenuItem)item.Parent;
int i = par.Index;
int j = item.Index;
string iDll = mDlls[i][j];
string iClass = iDll.Substring(0,iDll.IndexOf("."))
+ "."
+ iDll.Substring(0,iDll.IndexOf("."));
string iFunc = mFuncs[i][j];
try
{
Assembly asm = Assembly.LoadFrom(iDll);
Type mytype = asm.GetType(iClass);
MethodInfo mi = mytype.GetMethod(iFunc);
object obj = Activator.CreateInstance(mytype);
mi.Invoke(obj,new object[] {this});
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}//End菜单事件
#endregion
//真实情况权限信息应该在登录后取出,这里只是模拟
private string rightStr = "/B/C/";
读取菜单文件dymenu.xml#region 读取菜单文件dymenu.xml
/**//// <summary>
/// 读取菜单文件dymenu.xml
/// </summary>
XmlDocument doc = new XmlDocument();
public void ReadXml()
{
try
{
doc.Load("dymenu.xml");
}
catch(Exception e)
{
MessageBox.Show(e.Message);
}
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("主菜单");
mMenus = new string[nodes.Count];
bMenus = new bool[nodes.Count];
for(int i=0; i<nodes.Count; i++)
{
bMenus[i] = false;
}
mItems = new string[nodes.Count][];
mDlls = new string[nodes.Count][];
mFuncs = new string[nodes.Count][];
mRight = new string[nodes.Count][];
int j=0;
//foreach(XmlNode node in nodes)
for(int l=0; l< nodes.Count; l++)
{
XmlNodeList ns = nodes[l].SelectNodes("菜单Right");
XmlNodeList ns1 = nodes[l].SelectNodes("子菜单");
XmlNodeList ns2 = nodes[l].SelectNodes("菜单DLL");
XmlNodeList ns3 = nodes[l].SelectNodes("菜单Func");
for(int k=0; k<ns.Count; k++)
{
if(rightStr.IndexOf("/" + ns.Item(k).InnerXml.Trim() + "/") == -1)
{
nodes[l].RemoveChild(ns.Item(k));
int count = ns1.Count + ns2.Count + ns3.Count;//很奇怪,不调用一下count属性直接用item(k)会未将对象引用设置到对象实例
nodes[l].RemoveChild(ns1.Item(k));
nodes[l].RemoveChild(ns2.Item(k));
nodes[l].RemoveChild(ns3.Item(k));
}
}
//nodes[l].InnerText = nodes[l].InnerText.Trim();//Trim()之后获取不到子菜单,下面语句将无效,不Trim()会有空结构
XmlNodeList s1 = nodes[l].SelectNodes("子菜单");
if(s1.Count > 0)
{
XmlNodeList s2 = nodes[l].SelectNodes("菜单DLL");//要重新获取一次
XmlNodeList s3 = nodes[l].SelectNodes("菜单Func");
mMenus[j] = nodes[l].InnerXml.Substring(0,nodes[l].InnerXml.IndexOf("<")).Trim();
bMenus[j] = true;
int i=0;
mItems[j] = new string[s1.Count];
foreach(XmlNode n in s1)
{
mItems[j][i] = n.InnerXml.Trim();
i++;
}
i=0;
mDlls[j] = new string[s2.Count];
foreach(XmlNode n in s2)
{
mDlls[j][i] = n.InnerXml.Trim();
i++;
}
i=0;
mFuncs[j] = new string[s3.Count];
foreach(XmlNode n in s3)
{
mFuncs[j][i] = n.InnerXml.Trim();
i++;
}
j++;
}
else
{
//MessageBox.Show(nodes[l].InnerText);
}
}
//doc.Save("dymenu.xml");
}
#endregion
private void MainForm_Load(object sender, System.EventArgs e)
{
}
private void MainForm_Closed(object sender, System.EventArgs e)
{
Application.Exit();
}
private void toolBar1_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
if(e.Button.Text == "退出")
Application.Exit();
if (this.ActiveMdiChild is IMdiFunc)
{
((IMdiFunc)this.ActiveMdiChild).MdiParentToolBarOnClick(e.Button.Text.ToString());
}
}//End读取
}
}
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Reflection;
using System.Xml;
using Interface;
namespace DynamicMenus
{
/**//// <summary>
/// MainForm 的摘要说明。
/// </summary>
public class MainForm : System.Windows.Forms.Form
{
private System.Windows.Forms.MainMenu mainMenu1;
//主菜单
private string[] mMenus;
//主菜单状态
private bool[] bMenus;
//子菜单
private string[][] mItems;
//子菜单对应的dll
private string[][] mDlls;
//子菜单对应的函数
private string [][] mFuncs;
private string [][] mRight;
private OfficeMenus.OfficeMenus officeMenus1;
private System.Windows.Forms.ToolBar toolBar1;
private System.Windows.Forms.ToolBarButton tbbAdd;
private System.Windows.Forms.ToolBarButton tbbModify;
private System.Windows.Forms.ToolBarButton tbbDelete;
private System.Windows.Forms.ToolBarButton tbbSave;
private System.Windows.Forms.ToolBarButton tbbExit;
private System.ComponentModel.IContainer components;
public MainForm()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
OrtherInitialize();
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}
/**//// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
Windows 窗体设计器生成的代码#region Windows 窗体设计器生成的代码
/**//// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.officeMenus1 = new OfficeMenus.OfficeMenus(this.components);
this.mainMenu1 = new System.Windows.Forms.MainMenu(this.components);
this.toolBar1 = new System.Windows.Forms.ToolBar();
this.tbbAdd = new System.Windows.Forms.ToolBarButton();
this.tbbModify = new System.Windows.Forms.ToolBarButton();
this.tbbDelete = new System.Windows.Forms.ToolBarButton();
this.tbbSave = new System.Windows.Forms.ToolBarButton();
this.tbbExit = new System.Windows.Forms.ToolBarButton();
this.SuspendLayout();
//
// officeMenus1
//
this.officeMenus1.ImageList = null;
//
// toolBar1
//
this.toolBar1.Buttons.AddRange(new System.Windows.Forms.ToolBarButton[] {
this.tbbAdd,
this.tbbModify,
this.tbbDelete,
this.tbbSave,
this.tbbExit});
this.toolBar1.DropDownArrows = true;
this.toolBar1.Location = new System.Drawing.Point(0, 0);
this.toolBar1.Name = "toolBar1";
this.toolBar1.ShowToolTips = true;
this.toolBar1.Size = new System.Drawing.Size(584, 41);
this.toolBar1.TabIndex = 1;
this.toolBar1.ButtonClick += new System.Windows.Forms.ToolBarButtonClickEventHandler(this.toolBar1_ButtonClick);
//
// tbbAdd
//
this.tbbAdd.Name = "tbbAdd";
this.tbbAdd.Text = "新增";
//
// tbbModify
//
this.tbbModify.Name = "tbbModify";
this.tbbModify.Text = "修改";
//
// tbbDelete
//
this.tbbDelete.Name = "tbbDelete";
this.tbbDelete.Text = "删除";
//
// tbbSave
//
this.tbbSave.Name = "tbbSave";
this.tbbSave.Text = "保存";
//
// tbbExit
//
this.tbbExit.Name = "tbbExit";
this.tbbExit.Text = "退出";
//
// MainForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(584, 341);
this.Controls.Add(this.toolBar1);
this.IsMdiContainer = true;
this.Name = "MainForm";
this.Text = "基于组件装配的企业信息系统";
this.Closed += new System.EventHandler(this.MainForm_Closed);
this.Load += new System.EventHandler(this.MainForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private void OrtherInitialize()
{
//
//动态生成菜单
//
ReadXml(); //从菜单定义文件dymenu.xml中读取数据放入定义菜单的数组中
//从数组中取出菜单定义动态生成菜单
for(int i=0;i<mMenus.Length;i++)
{
if(bMenus[i])
{
MenuItem newDyMainItem = new MenuItem(mMenus[i]);
this.mainMenu1.MenuItems.Add(newDyMainItem);
for(int j=0;j<mItems[i].Length;j++)
{
MenuItem newDyItem = new MenuItem(mItems[i][j]);
newDyMainItem.MenuItems.Add(newDyItem);
//将每个菜单的Click事件指向同一个方法
newDyItem.Click += new System.EventHandler(this.NewClick);
}
}
}//End
//这里可以添加一些固定的菜单(不要定义index值,而且一定要在动态生成菜单的后面加,因为后面Click事件判断是按index的值来确定的)
this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {});
this.Menu = mainMenu1;
}
/**//// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new MainForm());
}
使用反射生成菜单事件#region 使用反射生成菜单事件
/**//// <summary>
/// 使用反射生成菜单事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void NewClick(object sender, System.EventArgs e)
{
MenuItem item = (MenuItem)sender;
MenuItem par = (MenuItem)item.Parent;
int i = par.Index;
int j = item.Index;
string iDll = mDlls[i][j];
string iClass = iDll.Substring(0,iDll.IndexOf("."))
+ "."
+ iDll.Substring(0,iDll.IndexOf("."));
string iFunc = mFuncs[i][j];
try
{
Assembly asm = Assembly.LoadFrom(iDll);
Type mytype = asm.GetType(iClass);
MethodInfo mi = mytype.GetMethod(iFunc);
object obj = Activator.CreateInstance(mytype);
mi.Invoke(obj,new object[] {this});
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}//End菜单事件
#endregion
//真实情况权限信息应该在登录后取出,这里只是模拟
private string rightStr = "/B/C/";
读取菜单文件dymenu.xml#region 读取菜单文件dymenu.xml
/**//// <summary>
/// 读取菜单文件dymenu.xml
/// </summary>
XmlDocument doc = new XmlDocument();
public void ReadXml()
{
try
{
doc.Load("dymenu.xml");
}
catch(Exception e)
{
MessageBox.Show(e.Message);
}
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("主菜单");
mMenus = new string[nodes.Count];
bMenus = new bool[nodes.Count];
for(int i=0; i<nodes.Count; i++)
{
bMenus[i] = false;
}
mItems = new string[nodes.Count][];
mDlls = new string[nodes.Count][];
mFuncs = new string[nodes.Count][];
mRight = new string[nodes.Count][];
int j=0;
//foreach(XmlNode node in nodes)
for(int l=0; l< nodes.Count; l++)
{
XmlNodeList ns = nodes[l].SelectNodes("菜单Right");
XmlNodeList ns1 = nodes[l].SelectNodes("子菜单");
XmlNodeList ns2 = nodes[l].SelectNodes("菜单DLL");
XmlNodeList ns3 = nodes[l].SelectNodes("菜单Func");
for(int k=0; k<ns.Count; k++)
{
if(rightStr.IndexOf("/" + ns.Item(k).InnerXml.Trim() + "/") == -1)
{
nodes[l].RemoveChild(ns.Item(k));
int count = ns1.Count + ns2.Count + ns3.Count;//很奇怪,不调用一下count属性直接用item(k)会未将对象引用设置到对象实例
nodes[l].RemoveChild(ns1.Item(k));
nodes[l].RemoveChild(ns2.Item(k));
nodes[l].RemoveChild(ns3.Item(k));
}
}
//nodes[l].InnerText = nodes[l].InnerText.Trim();//Trim()之后获取不到子菜单,下面语句将无效,不Trim()会有空结构
XmlNodeList s1 = nodes[l].SelectNodes("子菜单");
if(s1.Count > 0)
{
XmlNodeList s2 = nodes[l].SelectNodes("菜单DLL");//要重新获取一次
XmlNodeList s3 = nodes[l].SelectNodes("菜单Func");
mMenus[j] = nodes[l].InnerXml.Substring(0,nodes[l].InnerXml.IndexOf("<")).Trim();
bMenus[j] = true;
int i=0;
mItems[j] = new string[s1.Count];
foreach(XmlNode n in s1)
{
mItems[j][i] = n.InnerXml.Trim();
i++;
}
i=0;
mDlls[j] = new string[s2.Count];
foreach(XmlNode n in s2)
{
mDlls[j][i] = n.InnerXml.Trim();
i++;
}
i=0;
mFuncs[j] = new string[s3.Count];
foreach(XmlNode n in s3)
{
mFuncs[j][i] = n.InnerXml.Trim();
i++;
}
j++;
}
else
{
//MessageBox.Show(nodes[l].InnerText);
}
}
//doc.Save("dymenu.xml");
}
#endregion
private void MainForm_Load(object sender, System.EventArgs e)
{
}
private void MainForm_Closed(object sender, System.EventArgs e)
{
Application.Exit();
}
private void toolBar1_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
if(e.Button.Text == "退出")
Application.Exit();
if (this.ActiveMdiChild is IMdiFunc)
{
((IMdiFunc)this.ActiveMdiChild).MdiParentToolBarOnClick(e.Button.Text.ToString());
}
}//End读取
}
}