一步一步學習開發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模塊中的所有錯誤,避免因模塊出錯整個平台崩掉,由於篇幅限制這些內容下一篇來介紹。

本篇源碼下載地址:http://files.cnblogs.com/legweifang/WinAppDynamicDemo.rar


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM