最近需要写一个管理程序,因为以后可能需要升级不同功能,因此想只写一个框架界面,以后不同功能和界面以dll插件的形式升级。当框架界面启动时检测到目录下有dll时,就通过不同tab页面加载dll中的功能显示出来。这样如何实现呢?如果有简单示例代码就更好了。谢谢各位了

解决方案 »

  1.   

    给你举一个例子。假设你的屏幕有一个菜单树,显示一些用户关心的对象的分类列表,然后在树的旁边有一个大的区域动态加载不同的用户控件,那么你可以在你的保存树的节点的数据库(不管它是关系数据库、文本文件、Excel表,还是什么别的,反正都是数据库)中在每一个节点的名字的旁边另外设计一个叫做“UI Type Name”的字段,来保存用户界面的类型信息。然后你的树控件捕获到节点被点击以后,可以读取节点所对应的 UI 类型信息,例如private void treeview_NodeSelected(object sender, EventArgs e)
    {
        var typeName = 查询节点对应的UI类型信息(treeview1.SelectedValue);
        var ts = typeName = typeName.Split(',');
        var asm = Assembly.LoadFrom(ts[1]);
        var ctrl = (UserControl)Activator.CreateInstance(asm.GetType(ts[0]));
        Panel1.Controls.Clear();
        Panel1.Controls.Add(ctrl);
    }而假设你的主程序有A、B、C三类数据资料,你还可以进一步为ctrl按需传入数据资料,例如:void treeview_NodeSelected(object sender, EventArgs e)
    {
        var typeName = 查询节点对应的UI类型信息(treeview1.SelectedValue);
        var ts = typeName = typeName.Split(',');
        var asm = Assembly.LoadFrom(ts[1]);
        var ctrl = (UserControl)Activator.CreateInstance(asm.GetType(ts[0]));
        Panel1.Controls.Clear();
        Panel1.Controls.Add(ctrl);
        var ca = ctrl as IRequireDatasA;
        if(ca !=null)
            ca.SetDatas(this.DataA);
        var cb = ctrl as IRequireDatasB;
        if(cb !=null)
            cb.SetDatas(this.DataB);
        var cc = ctrl as IRequireDatasC;
        if(cc !=null)
            vc.SetDatas(this.DataC);
    }
    根据接口编程,那么你的主程序可以如此这样地捕获 ctrl 的接口,调用其相应的各种方法、属性、事件交互,等等。这个例子实在是太土了。其实越是简单的设计,越难以举例。一个非常基本的设计知识它越是“土”(而不是那种臃肿的时髦框架),你要理解并且使用它就越需要智慧。
      

  2.   

    说白了,就是把类型配置信息写到文件、数据库、通讯记录等等这类地方,而不是硬编码在你的程序里。这实在是没有太多技术,也不太需要发明什么雷人的“设计模式”名词儿。但是这是任何一个可扩展架构的基础知识。如果你希望找到微软的教材,那么你可以看看各种关于 MEF 的文章。虽然例子很少,但是它正是集中在你这个问题上没有跑题的。
      

  3.   

    这几天把代码调了下,可以动态显示加载的dll中界面。但是问题是,当动态加载多个dll的时候,只能正常显示第一个tab页(也就是第一个加载的dll界面)。后面虽然生成了tab页,但是并没有正常显示出tab的内容。找了半天也没找到办法,分不多,只能在这里追问下,请各位指点。若需要分,另开贴散分。谢谢。
    代码如下:if (info.Extension.Equals(".ocx")) //如果扩展名为".ocx"
                        {
                            //加载控件
                            Assembly assembly = Assembly.LoadFrom(path + @"/" + info.Name);
                            //获得类(型)
                            Type type = assembly.GetType("PluginsModel.PluginControl", false, true);
                            //设置筛选标志
                            BindingFlags bflags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
                            //调用构造函数并获得对象
                            Object obj = type.InvokeMember("PluginControl", bflags | BindingFlags.CreateInstance, null, null, new object[] { m_dbAddr , m_dbPort , m_dbUserName , m_dbPassword });
                            //将对象转换类型
                            UserControl control = (UserControl)obj;
                            control.Dock = DockStyle.Fill;
                            control.Visible = true;
                            TabPage tmpTabPage = new TabPage(info.Name.Substring(0, (info.Name.Length - 4)));
                            tmpTabPage.Name = info.Name;
                            
                            this.MainFormTabControl.Controls.Add(tmpTabPage);
                            tmpTabPage.Controls.Add(control);
                        }也就是说每个单独的dll都可以正常加载,但是循环加载后,后面的就不能正常显示了。
      

  4.   

    跟了一下,发现在示例代码第4行,当加载第一个ocx时,assembly可以正常加载1.ocx.
    但是当加载第二个ocx时,assembly还是加载的1.ocx。所以后面的ocx都显示的是第一个界面。这是为什么呢?
    这里的ocx就是dll。做了个扩展名的区别而已。