我在项目里面用到了LumiSoft.UI.Controls.WOutlookBar,效果如图所示,如果写死的话那当然是没问题,
但是我想根据用户登录的用户名查询到当前用户能够访问的菜单列表,然后把这些菜单列表动态的添加到界面上,
这一步已经做好了,现在就是当用户点击那个菜单图标的时候如何去打开对应的窗体呢?总不能在代码里面写死了吧,
我的设想是写一个公共的方法,然后有一个窗体类型的参数,但是貌似也不好实现,关键是要用到ShowFunction()这种方法。
请各位帮忙出个主意,万分感谢。
//这一段代码就是那个菜单图标的点击事件,
private void wOutlookBar_ItemClicked(object sender, LumiSoft.UI.Controls.WOutlookBar.ItemClicked_EventArgs e)
{
switch (e.Item.Caption)
{
case "菜单设置":
allensingleton.m_FrmMain.ShowFunction();
return;
case "系 统用 户":
allensingleton.m_FrmMain.ShowSysUser();
return;
case "用户组设置":
allensingleton.m_FrmMain.ShowUserGroup();
return;
case "权 限设 置":
allensingleton.m_FrmMain.ShowSetRole();
return;
}
}
这些显示窗体的代码是这样的,以ShowFunction为例:
private SystemTools.FrmFunction m_Function = new SystemTools.FrmFunction();
public void ShowFunction()
{
if (m_Function == null || m_Function.IsDisposed)
{
m_Function = new Allen.Tools.SystemTools.FrmFunction();
}
m_Function.AutoHidePortion = 0.15;
m_Function.Show(dockPanel, DockState.Document);
}
窗体加载的时候如果是管理员则会额外添加几个菜单出来:
private void FrmTools_Load(object sender, EventArgs e)
{
if (allensingleton.RoleName.ToUpper() == "ADMINISTRATOR")
{
bar = _outlookBar.Bars.Add("系统设置");
bar.ItemsStyle = ItemsStyle.IconSelect;
it = bar.Items.Add("菜单设置", 20);
it.AllowStuck = false;
it = bar.Items.Add("系 统用 户", 19);
it.AllowStuck = false;
it = bar.Items.Add("用户组设置", 23);
it.AllowStuck = false;
it = bar.Items.Add("权 限设 置", 06);
it.AllowStuck = false;
}
}
将每个可以用于显示的窗体的类型名与菜单列表相关联,然后,使用反射去建立相应的窗体
感谢各位的回答,
我数据库里面的每一个菜单都是对应了一个窗体名称的,通过菜单是可以得到对应的窗体名称的,
点击图标的时候我就想从数据库获得这个图标对应的窗体名称,但是显示窗体的时候一定 要按照
下面的方式。
public void ShowFunction()
{
if (m_Function == null || m_Function.IsDisposed)
{
m_Function = new Allen.Tools.SystemTools.FrmFunction();
}
m_Function.AutoHidePortion = 0.15;
m_Function.Show(dockPanel, DockState.Document);
}
大家觉得这样能不能实现?
@Allen_Chen: 注意先添加using System.Reflection;
public void ShowFunction(string frmName) { if(!m_Function.ContainsKey(frmName)) { m_Function.Add(frmName,null); } if (m_Function[frmName] == null || m_Function[frmName].IsDisposed) { m_Function[frmName] = Activator.CreateInstance(assemblyName,frmName) as Form; } m_Function[frmName].AutoHidePortion = 0.15; m_Function[frmName].Show(dockPanel, DockState.Document); } public Dictionary<string,Form> m_Function=new Dictionary<string,Form>;
具体类型,请自行修改
HI,@sinhbv:
我的每一个窗体都是继承了我写的 一个类了,如下:
public partial class FrmFunction : Allen.FrmBase.DockContent
{
}
如果没有继承的话那么下面两句话是执行不了的:
m_Function[frmName].AutoHidePortion = 0.15;
m_Function[frmName].Show(dockPanel, DockState.Document);
也就是说这个公共的方法貌似只能接受已经继承过我写的那个类的窗体,无法接受变量啊。
@Allen_Chen: 。。。。你把Form换成你的基类不就好了么
@sinhbv:
你是说直接继承Form?不用继承我自己写的那个类了吗?
@Allen_Chen:
Allen.FrmBase.DockContent是你的基类么?
那就应该是:
m_Function[frmName] = Activator.CreateInstance(assemblyName,frmName) as Allen.FrmBase.DockContent;
public Dictionary<string,Allen.FrmBase.DockContent> m_Function=new Dictionary<string,Allen.FrmBase.DockContent>;
@sinhbv:
哦,明白,那个assemblyName表示什么参数?
@Allen_Chen: 程序集名
明白assemblyName了,是AssemblyName,谢谢啊,
@sinhbv:
谢谢你的耐心回答!
程序集名?那我传入什么样子的参数呢?改为AssemblyName报错了,
@Allen_Chen:
是和主窗体在同一程序集中么?是的话,Assembly.GetExecutingAssembly().GetName().Name
@sinhbv:
麻烦你帮我看看,我按照你的意思改过来之后提示这个错误,我不明白这里应该用到什么类型。
这个提示: 无法通过引用转换、装箱转换、取消装箱转换、包装转换或 Null 类型转换将类型“System.Runtime.Remoting.ObjectHandle”转换为“Allen.FrmBase.DockContent”
@Allen_Chen: 这个是类型转换的问题,某些情况下不能用as去转换,改成
(Allen.FrmBase.DockContent) Activator.CreateInstance(assemblyName,frmName);
应该就可以了
@sinhbv: 好像这两个不能互相转换啊,
无法将类型“System.Runtime.Remoting.ObjectHandle”转换为“Allen.FrmBase.DockContent”
@Allen_Chen: 好吧,这个地方是有点错误,刚看了一下这个函数的返回类型居然不是object,所以再加个转换吧。如下:
ObjectHandle obj =Activator.CreateInstance(assemblyName,frmName);
m_Function[frmName]= (Allen.FrmBase.DockContent) obj.Unwrap();
使用反射。
1——
可以把窗体类型完整名信息放在列表项信息中,然后通过Type.GetType这个方法来获取类型,再构建类型实例。
2——
可以把加载这个窗体的函数名放在列表项信息中,然后通过反射机制获取具体的方法对象(可以在初始化的时候实现这个名称到方法对象的实例化),再运行这个方法来实现。
您好,能将第一种方法详细说一下吗?或者写两句关键代码我看看。谢谢!
@Allen_Chen:
比如你的窗体是Form1,窗体的类型名是MyNamespace.Form1,窗体所在的模块为MyModule,那么类型名就是:
MyNamespace.Form1, MyModule
这样,你构建列表项的时候,可以让对象的Tag的值为这个类型名。
当一个列表项被点击的时候,获取这个Tag值,如果是字符串,则通过Type.GetType(Tag as string)来获得类型,并覆盖原来的Tag值存储起来。通过这个步骤,我们就获得了目标窗体的类型了。
有了Type,那就简单,一般这样的窗体在定义的时候都会有一致的构造函数,此时,只需要获得构造函数即可:
type.GetContructor(...)
再对这个构造函数执行Invoke,则可以获得一个目标窗体对象,强制转换为Form或你自己定义的某一个窗体基类类型,再进行操作就好。
用工厂吧 我刚写了半天有点没思路
我就是需要你能给我点思路啊,3Q啊
@Allen_Chen:
你把那个图标的tag值填写为要show出的窗体对象名
比如:当你点击一长QQlog图片时 你要show的窗体叫QQLogForm 那你就把QQlog图片那个控件的tag赋值为QQlogForm 大小写一样
下面你就可以用反射来实现创建窗体对象了
Form f=Activator.CreateInstance(图片.tag) as Form;
f.show()
就会显示图标所对应的窗体了 不用判断
一個可以創建一個list列表。通過列表來操作類。這個可以 通過配置文件來實現。或則用工廠來初始化。
另一個是通過反射。