• 一步一步学习开发BPM工作流系统(三)开发WinForm的应用平台1


    前面介绍过BPM有很多模块,这些模块都是C/S的,需要有一个应用平台来管理这些模块,如果你想自己开发B/S的,可以略过该篇。

    我们先来看一下要开发的应用平台都有哪些功能?

    首先要有一个主程序,是一个可执行的exe文件,指定统一的调用接口,可以调用实现该接口的Dll,配置信息写入数据库。有了这个应用平台,你可以任意的配置应用模块,用户需要那个给他们配置那个,方便管理和升级。

    废话不多说,先看一下我们要做的应用平台的主界面。如下图:

    image

    左侧是导航树,右侧是工作区,整个主界面采用MDI的方式。主要用到的技术:反射动态调用dll.

    本节内容包括:

    一、反射技术的应用,将深入介绍程序集、类和方法的获取方法,以及如何过滤掉无用的类和方法名。

    二、应用模块开发,通过一个demo介绍如何开发应用模块。

    一、反射技术的应用

         反射是一个比较高级的用法,它可以在运行期加载程序集,增加了程序的灵活性,关于反射的原理和相关知识这里不多讲,只讲几个用到的方法。

         如何加载一个程序集?程序集是一个Dll文件也可以是一个EXE文件,总之只要是.Net编写的就可以。反射调用的原理是首先加载程序集文件到内存中,然后从内存中取到程序集中的类,并实例化类,然后取到类中的方法,就可以调用这个方法了,调用的时候,参数必须保持与程序集中的参数位置个数一致。在应用平台中,我们需要动态调用情况包括:动态调用一个窗体,动态调用一个方法,窗体又包括MDI类型和SDI类型,所以我们需要提供几个动态调用的方法。下面的代码动态调用一个MDI窗体。

            /// <summary>
            /// MDI方式动态调用dll中的窗体,只使用于winform.
            /// </summary>

    public  System.Windows.Forms.Form CallMDIWindows()
            {
                if (_DllFileName.Trim().Length==0||_DllFileName==null) throw new Exception("CallMDIWindows调用失败,DllName 不允许为空!");
                if (_DllClassName.Trim().Length==0||_DllClassName==null) throw new Exception("CallMDIWindows调用失败,DllClassName 不允许为空!");
                if (_MainForm==null)throw new Exception("CallMDIWindows调用失败,MainForm没有指定!");
                if (!File.Exists(_DllFileName)) throw new Exception("CallMDIWindows调用失败,[" _DllFileName "]不存在。");
                try
                {
                    System.Windows.Forms.Form fromCtrl = null;
                    Assembly assembly = Assembly.LoadFile(_DllFileName);//从文件中加载一个程序集
                    Type tp=assembly.GetType(_DllClassName);//获取到要使用的类名,这里是一个窗体类
                    if (_ObjArray==null)//如果窗体类的构造函数不需要参数,这里要与窗体类保持一致
                        fromCtrl = ( System.Windows.Forms.Form)Activator.CreateInstance(tp);//实例化这个类,得到一个窗体的实例
                    else//窗体类的构造函数需要参数,这里要与窗体类保持一致
                        fromCtrl = (System.Windows.Forms.Form)Activator.CreateInstance(tp, _ObjArray);//实例化这个类,得到一个窗体的实例
                    fromCtrl.MdiParent=_MainForm;//MDI的主窗体
                    fromCtrl.Show();//打开这个窗体
                    return fromCtrl;//返回该窗体的引用
                }
                catch(Exception ex)
                {
                    throw ex;
    
                }
            }

    下面的代码调用一个SDI窗体

    /// <summary>
            /// SDI方式动态调用dll中的窗体,只使用于winform.
            /// </summary>
            public System.Windows.Forms.Form  CallSDIWindows()
            {
                if (_DllFileName.Trim().Length==0||_DllFileName==null) throw new Exception("CallSDIWindows调用失败,DllName 不允许为空!");
                if (_DllClassName.Trim().Length==0||_DllClassName==null) throw new Exception("CallSDIWindows调用失败,_DllClassName 不允许为空!");
                if (!File.Exists(_DllFileName)) throw new Exception("CallSDIWindows调用失败,[" _DllFileName "]不存在。");
                try
                {
                    System.Windows.Forms.Form fromCtrl = null;
                    Assembly assembly = Assembly.LoadFile(_DllFileName);//从文件中加载一个程序集
                    Type tp = assembly.GetType(_DllClassName);//获取到要使用的类名,这里是一个窗体类
                    if (_ObjArray == null)//如果窗体类的构造函数不需要参数,这里要与窗体类保持一致
                        fromCtrl = ( System.Windows.Forms.Form)Activator.CreateInstance(tp);
                    else//窗体类的构造函数需要参数,这里要与窗体类保持一致
                    fromCtrl = ( System.Windows.Forms.Form)Activator.CreateInstance(tp,_ObjArray);
                    fromCtrl.ShowDialog();
                    return fromCtrl;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
    
            }

    下面的代码调用一个方法

    /// <summary>
            /// 动态调用dll类中的方法
            /// </summary>
            /// <returns></returns>
            public object CallMethod()
            {
                if (_DllFileName.Trim().Length==0||_DllFileName==null) throw new Exception("CallMethod调用失败,DllName 不允许为空!");
                if (_DllClassName.Trim().Length==0||_DllClassName==null) throw new Exception("CallMethod调用失败,_DllClassName 不允许为空!");
                if (_DllMethodName.Trim().Length==0||_DllMethodName==null) throw new Exception("CallMethod调用失败,DllMethodName 不允许为空!");
                if (!File.Exists(_DllFileName)) throw new Exception("CallMethod调用失败,[" _DllFileName "]不存在。");
                object obj=null;
                try
                {
                    Assembly assembly = Assembly.LoadFile(_DllFileName);//从文件中加载一个程序集
                    Type tp = assembly.GetType(_DllClassName);//获取到要使用的类名,这里是一个窗体类
                    MethodInfo mi=tp.GetMethod(_DllMethodName);//从类中获取要调用的方法名
                    if (_ObjArray==null)//类的实例化不需要参数
                        obj = (object)Activator.CreateInstance(tp);
                    else //类的实例化需要参数
                        obj = (object)Activator.CreateInstance(tp,_ObjArray);
                    return mi.Invoke(obj,_ObjMethodArray);//这里默认方法都需要参数
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            } 

    这里需要注意的几点:

    1、Dll在加载前可以覆盖和删除,一旦加载即处于使用状态无法删除,所以要替换Dll的时候需要先关闭主程序。

    2、获取类名的时候,类的名称必须带有完整的命名空间

    我们先来学习动态调用,具体的开发过程如下:

    第一步:我们先来做一个主应用程序,如下图:

    image

    第二步:我们开发一个测试的TestDll,界面如下图:

    image

    该窗体提供一个带参数的构造函数和一个Add方法。代码如下:

    public partial class Form1 : Form
        {
            string _userName = "";
            public Form1()
            {
                InitializeComponent();
            }
            public Form1(string userName)
            {
                InitializeComponent();
                _userName = userName;
                label1.Text = _userName;
            }
            private void button1_Click(object sender, EventArgs e)
            {
                MessageBox.Show(_userName ",调用Ok了!");
            }
            public int Add(int a, int b)
            {
                return a +b;
            }
        }

    第三步:编译TestDll,把TestDll.dll文件拷贝到第一步创建的主应用程序目录下。

    第四步:在主应用程序三个按钮分别写如下代码:

    private void toolStripButton2_Click(object sender, EventArgs e)
            {
                //打开一个dll中的MDI窗体
                DynamicLibrary dyl = new DynamicLibrary();
                Object[] objArray = new object[1];//dll中类构造函数必须具有的参数数组
                objArray[0] = "云飞扬";
                dyl.DllFileName =Application.StartupPath  "\\TestDll.dll";
                dyl.DllClassName = "TestDll.Form1";
                dyl.ObjArray = objArray;
                dyl.MainForm = this;//主窗体
                dyl.CallMDIWindows();
    
            }
    
            private void toolStripButton3_Click(object sender, EventArgs e)
            {
                //打开一个Dll中的SDI窗体
                DynamicLibrary dyl = new DynamicLibrary();
                Object[] objArray = new object[1];//dll中类构造函数必须具有的参数数组
                objArray[0] = "云飞扬";
                dyl.DllFileName = Application.StartupPath   "\\TestDll.dll";
                dyl.DllClassName = "TestDll.Form1";
                dyl.ObjArray = objArray;
                dyl.CallSDIWindows();
            }
    
            private void toolStripButton1_Click(object sender, EventArgs e)
            {
                //执行Dll中的一个方法
                DynamicLibrary dyl = new DynamicLibrary();
                Object[] objArray = new object[1];//dll中类构造函数必须具有的参数数组
                objArray[0] = "云飞扬";
                Object[] objArrayM = new object[2];//dll中Add方法用到的参数数组
                objArrayM[0] = 3;
                objArrayM[1] = 4;
                dyl.DllFileName = Application.StartupPath   "\\TestDll.dll";
                dyl.DllClassName = "TestDll.Form1";
                dyl.ObjArray = objArray;
                dyl.ObjMethodArray = objArrayM;
                dyl.DllMethodName="Add";
               object result= dyl.CallMethod();
               MessageBox.Show(result.ToString());
            }

    第五步:运行主应用程序,分别执行三个按钮,分别出现下面的三种效果,说明执行正确。

    调用Dll中的一个MDI窗体

    image

    调用Dll中的SDI窗体

    image

    执行一个Dll中的方法

    image

    我们成功的实现了动态调用的几种情况。窗体可以是任意复杂的窗体,方法可以是任意复杂的方法。这个Demo是学习一下利用反射实现动态调用,后面会有源码的下载。到这里我们只是学习了反射,WinForm应用平台的核心已经实现了,但要做成一个应用平台还有很多工作要做,比如dll如何配置,配置信息如何存放,打开的窗体如何判断是否已经存在,避免重复开启,还需要一个登录窗体,还需要一个扑捉错误的统一方法,可以破获dll模块中的所有错误,避免因模块出错整个平台崩掉,由于篇幅限制这些内容下一篇来介绍。

    本篇源码下载地址:https://files.cnblogs.com/legweifang/WinAppDynamicDemo.rar

    我的程序人生
  • 相关阅读:
    android studio中timber的配置
    bufferknife框架的正确使用方式 -终于他么知道了
    开源的图像滤镜库----for Android
    HSV做通道分离是出现的Vector内存越界错误
    HSV与RGB的相互转换的公式
    Windows下python的第三方库的安装
    Python出现"Non-ASCII character 'xe6' in file"错误解决方法
    Verilog的IDE Quartus II
    Java-ZipUtil工具类
    Java-JDBCUtil工具类
  • 原文地址:https://www.cnblogs.com/legweifang/p/2607438.html
Copyright © 2020-2023  润新知