在我們開發工作流的時候,往往需要設計到具體業務表單信息的編輯,有些是采用動態編輯的,有些則是在開發過程中處理的,各有各的優點,動態編輯的則方便維護各種各樣的表單,但是數據的綁定及處理則比較麻煩,而自定義開發的,則數據彈性很大,方便修改調整。本篇隨筆基於表單的開發設計過程,介紹在工作流中如何新增一個業務表單,以便快速的實現審批業務的上線處理。
1、業務表單的基類繼承
首先我們來了解一下業務表單的對應關系,一般創建一個業務流程處理,都需要有一個具體的創建業務表單的界面,以及一個查看處理表單的界面。
為了方便,我們盡可能減少代碼編寫,我們需要把大多數的邏輯處理放在基類實現,這樣我們在新增一個業務表單的時候就可以減少很多代碼編寫及維護了。
如對於FrmAddApply類定義如下,我們定義一些抽象接口用於下面的業務表單實現
/// <summary> /// 創建申請單的窗體基類 /// </summary> public partial class FrmAddApply : BaseForm { /// <summary> /// 表單ID /// </summary> public string FormID { get; set; } /// <summary> /// 申請單ID /// </summary> public string ApplyId { get; set; } public FrmAddApply() { InitializeComponent(); } /// <summary> /// 顯示數據的函數(子類必須實現) /// </summary> public virtual void DisplayData() { } /// <summary> /// 實現控件輸入檢查的函數(子類必須實現) /// </summary> /// <returns></returns> public virtual bool CheckInput() { return true; } /// <summary> /// 編輯狀態下的數據保存(子類必須實現) /// </summary> /// <returns></returns> public virtual bool SaveUpdated() { return true; } /// <summary> /// 新增狀態下的數據保存(子類必須實現) /// </summary> /// <returns></returns> public virtual bool SaveAddNew() { return true; } ...................
這樣我們創建一個新的業務表單,只需要利用代碼生成工具,生成所需要的各層框架代碼,然后再生成Winform窗體代碼,復制部分界面處理代碼過來這個業務表單的子類即可。
下面是一個請假申請的業務表單設計,如下所示。
我們看到這個表單可以使用代碼生成工具Database2Sharp快速生成后進行一定調整的,而這個編輯表單的界面,我們只需要使用自動生成的部分代碼即可。
相關代碼只需要復制上面的新增、更新、顯示數據的代碼即可。
對於查看申請單的基類FrmViewApply類,我們更加簡單,我們需要把它的自定義界面控件加載出來即可。
下面是查看申請單的基類,封裝了相關的處理邏輯。
/// <summary> /// 本窗體是通用的查看申請單界面基類。 /// 為減少開發相關頁面的工作量,只需要創建一個新窗體,並繼承本窗體,然后在子窗體Form_Load函數里面,初始化對應的申請單顯示控件即可。 /// </summary> public partial class FrmViewApply : BaseDock { /// <summary> /// 申請單ID /// </summary> public string ApplyId { get; set; } /// <summary> /// 申請單自定義控件 /// </summary> public BaseUserControl ApplyControl { get; set; } /// <summary> /// 默認構造函數 /// </summary> public FrmViewApply() { InitializeComponent(); } private void FrmViewApply_Load(object sender, EventArgs e) { if (!this.DesignMode) { InitToolBar(); } } /// <summary> /// 初始化申請單控件 /// </summary> protected virtual void InitApplyControl(BaseUserControl control) { if (control != null) { this.ApplyControl = control; this.ApplyControl.Dock = DockStyle.Fill; this.Controls.Add(control); } } /// <summary> /// 打印申請單控件內容(默認調用窗體打印) /// </summary> protected virtual void PrintApplyControl() { if(this.ApplyControl != null) { PrintFormHelper.Print(this.ApplyControl, false); } } /// <summary> /// 表單另存為 /// </summary> protected virtual void ApplySaveAs() { } /// <summary> /// 初始化工具欄的按鈕和狀態 /// </summary> protected virtual void InitToolBar() { ................//基類實現,控制什么時候該做什么審批處理,以及一些常見按鈕 } .................
查看請假申請單的窗口就是繼承這個FrmViewApply即可,如下所示。
/// <summary> /// 查看請假申請單的窗體 /// </summary> public partial class FrmViewLeave : FrmViewApply { private LeaveControl control = null; public FrmViewLeave() { InitializeComponent(); } private void FrmViewLeave_Load(object sender, EventArgs e) { //初始化控件並展示在基類窗體里面 control = new LeaveControl(); control.ApplyId = this.ApplyId; control.DisplayData(); base.InitApplyControl(control); } }
這個就是全部的窗體源碼了,主要的內容我們看到是在LeaveControl這個用戶控件類里面的了,
而這個控件主要就是上面編輯請假申請單的界面設計,並復制相關的顯示數據代碼即可。
相關界面代碼如下所示。
/// <summary> /// 查看請假申請單的內容顯示控件 /// </summary> public partial class LeaveControl : BaseUserControl { /// <summary> /// 申請單ID /// </summary> public string ApplyId { get; set; } public LeaveControl() { InitializeComponent(); SetReadOnly(); } /// <summary> /// 設置整個窗體布局為只讀並設置只讀的背景顏色 /// </summary> private void SetReadOnly() { this.layoutControl1.OptionsView.IsReadOnly = DevExpress.Utils.DefaultBoolean.True; this.layoutControl1.Appearance.ControlReadOnly.BackColor = Color.SeaShell; } private void LeaveControl_Load(object sender, EventArgs e) { this.applyInfoControl1.ApplyId = this.ApplyId; this.applyInfoControl1.BindData(); } /// <summary> /// 初始化數據字典 /// </summary> private void InitDictItem() { //初始化代碼 } /// <summary> /// 數據顯示的函數 /// </summary> public void DisplayData() { InitDictItem();//數據字典加載(公用) //由於申請單一般是用申請表單入口,而非業務數據表,因此只能傳入ApplyId獲取信息 if (!string.IsNullOrEmpty(ApplyId)) { .................... }
通過上面定義的對應表單的窗體基類,可以減少我們重復編碼的需要,我們只需要利用最有效率的生成界面,然后復制代碼后調整即可快速生成我們所需要的不同表單界面。
每個表單我們放在一個目錄上,這樣我們就可以很好管理它們了。
2、業務表單的動態展示處理
上面介紹了業務表單的填寫、查看兩個不同的窗口,我們在申請單的審批界面里面,統一顯示不同的表單,以及創建不同的業務表單界面,這種動態的處理可以實現不同業務表單的創建及顯示界面。
如我的審批工作中,表單的顯示界面如下所示,查看具體表單后,可以動態展示不同的業務窗口界面。
另外我們在創建業務表單的時候,根據數據庫的配置信息,動態展示所有可以展示的創建入口,單擊相關的按鈕,可以動態調用創建對應的表單界面。
創建流程業務表單的入口如下所示。
在我的審批工作界面,動態創建對應的查看表單窗體代碼如下所示。
/// <summary> /// 分頁控件編輯項操作 /// </summary> private void winGridViewPager1_OnEditSelected(object sender, EventArgs e) { //獲取記錄ID和表單ID string ID = this.winGridViewPager1.gridView1.GetFocusedRowCellDisplayText("ID"); string FormId = string.Concat(this.winGridViewPager1.gridView1.GetFocusedRowCellValue("FormId")); if (!string.IsNullOrEmpty(ID) && !string.IsNullOrEmpty(FormId)) { var formInfo = BLLFactory<BLL.Form>.Instance.FindByID(FormId); if (formInfo != null && !string.IsNullOrEmpty(formInfo.ApplyWin2)) { try { //根據配置的查看窗體,動態構建查看申請單對象 FrmViewApply dlg = Assembly.GetExecutingAssembly().CreateInstance(formInfo.ApplyWin2) as FrmViewApply; if (dlg != null) { dlg.ApplyId = ID; dlg.OnDataSaved += new EventHandler(dlg_OnDataSaved); if (DialogResult.OK == dlg.ShowDialog()) { BindData(); } } } catch (Exception ex) { LogHelper.Error(ex); MessageDxUtil.ShowError(ex.Message); } } } }
這個代碼替代了需要手動創建不同對象的處理
var dlg = new FrmViewAssignWork(); dlg.ApplyId = ID; dlg.OnDataSaved += new EventHandler(dlg_OnDataSaved); if (DialogResult.OK == dlg.ShowDialog()) { BindData(); }
同理,對於創建編輯界面,我們也可以同樣的方法動態創建相關的編輯表單界面,如下代碼所示。
WInform開發框架之工作流系列文章: