如何通过名称来实例化一个对象

时间:2021-06-10 05:21:59

 我在做一个menubar ,menu 中的结构为这样的
  Menu 1
       Sub men 1
   Sub men 2
  Menu 2
       Sub men 1
   Sub men 2

   我现在想将 Menu 中的所有菜单存放在一个 XML 中
         <?xml version="1.0" encoding="gb2312"?>
<root>
  <Main_Menu>
       <Main_Menu_Item Menu_Title="Menu 1"  PointObject="men1">
          <Item Menu_Title=" Sub men 1" PointObject=" Submen1" />
          <Item Menu_Title=" Sub men 2" PointObject=" Submen2" />
    </Main_Menu_Item>
  <Main_Menu_Item Menu_Title="Menu 2"  PointObject="men2">
                              <Item Menu_Title=" Sub men 1" PointObject=" Submen1" />
          <Item Menu_Title=" Sub men 2" PointObject=" Submen2" />
    </Main_Menu_Item>
  </Main_Menu>
</root>

Menu_Title 为菜单所显示的标题, PointObject 为 对应 win form 的名称 eg : Submen1.cs  的PointObject 为 "Submen1"

现在的问题是: 当用户点击 "Menu 1" 下面的 "Sub men 1" 时如何根据 "Submen1"  这个名词来调用 Submen1.cs 

同时在显示Submen1 winform时制 同一个用户只能打开一次

16 个解决方案

#1


看标题应该用反射~~

但看楼主描述,似乎应该使用FindControl

#2


这段是自动生成菜单,并为每个菜单项生成事件的代码,是在vs2005里面写的,vs2003也是大同小异,里面的菜单名加载是引用资源里的文件,换成xml文件就行了。
        public static void AddSkinMenu(ToolStripMenuItem toolMenu)
        {
            DataSet skin = new DataSet();
            try
            {
                
                skin.ReadXml("skin.xml",XmlReadMode.Auto);
            }
            catch
            {

            }
            if (skin==null||skin.Tables.Count < 1)
            {
                skin = new DataSet();
                skin.Tables.Add("skin");
                skin.Tables["skin"].Columns.Add("style");
                System.Data.DataRow dr = skin.Tables["skin"].NewRow();
                dr[0] = "系统默认";
                skin.Tables[0].Rows.Add(dr);
                skin.WriteXml("skin.xml", XmlWriteMode.IgnoreSchema);
            }
            foreach (SkinType st in (SkinType[])System.Enum.GetValues(typeof(SkinType)))
            {
                toolMenu.DropDownItems.Add(new ToolStripMenuItem(st.ToString()));

                toolMenu.DropDownItems[toolMenu.DropDownItems.Count - 1].Click += new EventHandler(frm_Main_Click);
                if (st.ToString() == skin.Tables[0].Rows[0][0].ToString())
                {
                    ((ToolStripMenuItem)toolMenu.DropDownItems[toolMenu.DropDownItems.Count - 1]).Checked = true;
                    frm_Main_Click(toolMenu.DropDownItems[toolMenu.DropDownItems.Count - 1], null);

                }

            }
            
            toolMenu.DropDownItems.Add(new ToolStripMenuItem("系统默认"));
            toolMenu.DropDownItems[toolMenu.DropDownItems.Count - 1].Click += new EventHandler(frm_Main_Click);
            if (skin.Tables[0].Rows[0][0].ToString() == "系统默认")
            {
                ((ToolStripMenuItem)toolMenu.DropDownItems[toolMenu.DropDownItems.Count - 1]).Checked = true;
            }
            
           
            
        }

#3


to:  Sharp Shooter
 findcontrol 是行不通的,因为查找的对象不是个 control 而是一个尚未实例化的 对象引用

to: alldj(灵山妖姬) 
 你的方法是可行的但,不是我想要的,我现在关问题是 能否通对 Winform 的名称来实例化该对


望朋友帮忙

#4


用反射做
先把submen.cs编译成.dll放在bin里
然后加载。
Assembly a = Assembly.Load("namespace.submen1.dll");
(Form)Activator.CreateInstance(a.GetTypes()).ShowDialog();


#5


反射是可以,但是可能有些损耗性能

其实这种问题如果有个统一的命名规则的话、
直接findcontrol
或者将control和xml title 弄一个dictionary 调用
应该是个不错的解决方案

毕竟这样没有反射损耗性能

#6


如果你要调用的类直接就和主窗口在一个项目里的话,用
Assembly a = Assembly.GetExecutingAssembly()就可以获得当前的Assembly
然后Type t = a.GetType(类名)获得类(最好是带namespace的全名)
最后Activator.CreateInstance(t)即可,谨慎起见最好这三句套个try作意外处理

#7


测试中,谢谢大家的热心帮忙,测试完结贴,顶者有分

#8


private void button1_Click(object sender, EventArgs e)
        {
            string frm = "Form2";
            for (int i = 0; i < Application.OpenForms.Count; i++)
            {
                if (Application.OpenForms[i].Name == frm)
                {
                    return;
                }
            }
            System.Reflection.Assembly ass = System.Reflection.Assembly.GetExecutingAssembly();
            //object obj=thisDll.CreateInstance("Form2");
            Type typForm = ass.GetType( "testDLL."+frm );
            if( typForm == null ) return;
            Form frmTest = typForm.InvokeMember( null,BindingFlags.DeclaredOnly |BindingFlags.Public | BindingFlags.NonPublic |BindingFlags.Instance | BindingFlags.CreateInstance,null,null,null ) as Form;

            if( frmTest == null ) return;
            else
            {
                frmTest.Name=frm;
                frmTest.Show();
            }



        }

#9


可用类工厂

#10


不行,我在Vs2003中不能用OpenForms的属性

#11



        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", EntryPoint = "FindWindowEx")] //找子窗体
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("User32.dll", EntryPoint = "SendMessage")] //用于发送信息给窗体
        private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);




        /// <summary>
        /// 查找是否已创建窗体
        /// </summary>
        /// <param name="FormTitle">标题名称</param>
        /// <returns></returns>
        public static bool SearchForm(string FormTitle)
        {
            IntPtr ParenthWnd = new IntPtr(0);
            IntPtr EdithWnd = new IntPtr(0);

            //查到窗体,得到整个窗体 
            ParenthWnd = FindWindow(null,FormTitle);
            if (!ParenthWnd.Equals(IntPtr.Zero))
            {
                return true;
            }
            else
            {
                return false;
            }

        }


private void button1_Click(object sender, EventArgs e)
        {
            string frm = "FormTitle";
            if (SearchForm(frm))
{
    return;
}
frm="Form2";
            System.Reflection.Assembly ass = System.Reflection.Assembly.GetExecutingAssembly();
            //object obj=thisDll.CreateInstance("Form2");
            Type typForm = ass.GetType( "testDLL."+frm );
            if( typForm == null ) return;
            Form frmTest = typForm.InvokeMember( null,BindingFlags.DeclaredOnly |BindingFlags.Public | BindingFlags.NonPublic |BindingFlags.Instance | BindingFlags.CreateInstance,null,null,null ) as Form;

            if( frmTest == null ) return;
            else
            {
                frmTest.Name=frm;
                frmTest.Show();
            }



        }

#12


.net 反射机制

#13


to :alldj(灵山妖姬) 
找不到BindingFlags

#14


学习

#15


System.Reflection.BindingFlags 可以,测试中

#16


可以了,谢谢大家

to :alldj(灵山妖姬) 
你的方法可行

#1


看标题应该用反射~~

但看楼主描述,似乎应该使用FindControl

#2


这段是自动生成菜单,并为每个菜单项生成事件的代码,是在vs2005里面写的,vs2003也是大同小异,里面的菜单名加载是引用资源里的文件,换成xml文件就行了。
        public static void AddSkinMenu(ToolStripMenuItem toolMenu)
        {
            DataSet skin = new DataSet();
            try
            {
                
                skin.ReadXml("skin.xml",XmlReadMode.Auto);
            }
            catch
            {

            }
            if (skin==null||skin.Tables.Count < 1)
            {
                skin = new DataSet();
                skin.Tables.Add("skin");
                skin.Tables["skin"].Columns.Add("style");
                System.Data.DataRow dr = skin.Tables["skin"].NewRow();
                dr[0] = "系统默认";
                skin.Tables[0].Rows.Add(dr);
                skin.WriteXml("skin.xml", XmlWriteMode.IgnoreSchema);
            }
            foreach (SkinType st in (SkinType[])System.Enum.GetValues(typeof(SkinType)))
            {
                toolMenu.DropDownItems.Add(new ToolStripMenuItem(st.ToString()));

                toolMenu.DropDownItems[toolMenu.DropDownItems.Count - 1].Click += new EventHandler(frm_Main_Click);
                if (st.ToString() == skin.Tables[0].Rows[0][0].ToString())
                {
                    ((ToolStripMenuItem)toolMenu.DropDownItems[toolMenu.DropDownItems.Count - 1]).Checked = true;
                    frm_Main_Click(toolMenu.DropDownItems[toolMenu.DropDownItems.Count - 1], null);

                }

            }
            
            toolMenu.DropDownItems.Add(new ToolStripMenuItem("系统默认"));
            toolMenu.DropDownItems[toolMenu.DropDownItems.Count - 1].Click += new EventHandler(frm_Main_Click);
            if (skin.Tables[0].Rows[0][0].ToString() == "系统默认")
            {
                ((ToolStripMenuItem)toolMenu.DropDownItems[toolMenu.DropDownItems.Count - 1]).Checked = true;
            }
            
           
            
        }

#3


to:  Sharp Shooter
 findcontrol 是行不通的,因为查找的对象不是个 control 而是一个尚未实例化的 对象引用

to: alldj(灵山妖姬) 
 你的方法是可行的但,不是我想要的,我现在关问题是 能否通对 Winform 的名称来实例化该对


望朋友帮忙

#4


用反射做
先把submen.cs编译成.dll放在bin里
然后加载。
Assembly a = Assembly.Load("namespace.submen1.dll");
(Form)Activator.CreateInstance(a.GetTypes()).ShowDialog();


#5


反射是可以,但是可能有些损耗性能

其实这种问题如果有个统一的命名规则的话、
直接findcontrol
或者将control和xml title 弄一个dictionary 调用
应该是个不错的解决方案

毕竟这样没有反射损耗性能

#6


如果你要调用的类直接就和主窗口在一个项目里的话,用
Assembly a = Assembly.GetExecutingAssembly()就可以获得当前的Assembly
然后Type t = a.GetType(类名)获得类(最好是带namespace的全名)
最后Activator.CreateInstance(t)即可,谨慎起见最好这三句套个try作意外处理

#7


测试中,谢谢大家的热心帮忙,测试完结贴,顶者有分

#8


private void button1_Click(object sender, EventArgs e)
        {
            string frm = "Form2";
            for (int i = 0; i < Application.OpenForms.Count; i++)
            {
                if (Application.OpenForms[i].Name == frm)
                {
                    return;
                }
            }
            System.Reflection.Assembly ass = System.Reflection.Assembly.GetExecutingAssembly();
            //object obj=thisDll.CreateInstance("Form2");
            Type typForm = ass.GetType( "testDLL."+frm );
            if( typForm == null ) return;
            Form frmTest = typForm.InvokeMember( null,BindingFlags.DeclaredOnly |BindingFlags.Public | BindingFlags.NonPublic |BindingFlags.Instance | BindingFlags.CreateInstance,null,null,null ) as Form;

            if( frmTest == null ) return;
            else
            {
                frmTest.Name=frm;
                frmTest.Show();
            }



        }

#9


可用类工厂

#10


不行,我在Vs2003中不能用OpenForms的属性

#11



        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", EntryPoint = "FindWindowEx")] //找子窗体
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("User32.dll", EntryPoint = "SendMessage")] //用于发送信息给窗体
        private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);




        /// <summary>
        /// 查找是否已创建窗体
        /// </summary>
        /// <param name="FormTitle">标题名称</param>
        /// <returns></returns>
        public static bool SearchForm(string FormTitle)
        {
            IntPtr ParenthWnd = new IntPtr(0);
            IntPtr EdithWnd = new IntPtr(0);

            //查到窗体,得到整个窗体 
            ParenthWnd = FindWindow(null,FormTitle);
            if (!ParenthWnd.Equals(IntPtr.Zero))
            {
                return true;
            }
            else
            {
                return false;
            }

        }


private void button1_Click(object sender, EventArgs e)
        {
            string frm = "FormTitle";
            if (SearchForm(frm))
{
    return;
}
frm="Form2";
            System.Reflection.Assembly ass = System.Reflection.Assembly.GetExecutingAssembly();
            //object obj=thisDll.CreateInstance("Form2");
            Type typForm = ass.GetType( "testDLL."+frm );
            if( typForm == null ) return;
            Form frmTest = typForm.InvokeMember( null,BindingFlags.DeclaredOnly |BindingFlags.Public | BindingFlags.NonPublic |BindingFlags.Instance | BindingFlags.CreateInstance,null,null,null ) as Form;

            if( frmTest == null ) return;
            else
            {
                frmTest.Name=frm;
                frmTest.Show();
            }



        }

#12


.net 反射机制

#13


to :alldj(灵山妖姬) 
找不到BindingFlags

#14


学习

#15


System.Reflection.BindingFlags 可以,测试中

#16


可以了,谢谢大家

to :alldj(灵山妖姬) 
你的方法可行