前面介紹過BPM有很多模塊,這些模塊都是C/S的,需要有一個應用平台來管理這些模塊,如果你想自己開發B/S的,可以略過該篇。
我們先來看一下要開發的應用平台都有哪些功能?
首先要有一個主程序,是一個可執行的exe文件,指定統一的調用接口,可以調用實現該接口的Dll,配置信息寫入數據庫。有了這個應用平台,你可以任意的配置應用模塊,用戶需要那個給他們配置那個,方便管理和升級。
廢話不多說,先看一下我們要做的應用平台的主界面。如下圖:
左側是導航樹,右側是工作區,整個主界面采用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、獲取類名的時候,類的名稱必須帶有完整的命名空間
我們先來學習動態調用,具體的開發過程如下:
第一步:我們先來做一個主應用程序,如下圖:
第二步:我們開發一個測試的TestDll,界面如下圖:
該窗體提供一個帶參數的構造函數和一個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窗體
調用Dll中的SDI窗體
執行一個Dll中的方法
我們成功的實現了動態調用的幾種情況。窗體可以是任意復雜的窗體,方法可以是任意復雜的方法。這個Demo是學習一下利用反射實現動態調用,后面會有源碼的下載。到這里我們只是學習了反射,WinForm應用平台的核心已經實現了,但要做成一個應用平台還有很多工作要做,比如dll如何配置,配置信息如何存放,打開的窗體如何判斷是否已經存在,避免重復開啟,還需要一個登錄窗體,還需要一個撲捉錯誤的統一方法,可以破獲dll模塊中的所有錯誤,避免因模塊出錯整個平台崩掉,由於篇幅限制這些內容下一篇來介紹。
本篇源碼下載地址:http://files.cnblogs.com/legweifang/WinAppDynamicDemo.rar