ERP系統的單據具有標準的功能,這裏的單據可翻譯爲Bill,Document,Entry,具有類似的工具條操做界面。經過設計可複用的基類,子類只須要繼承基類窗體便可完成單據功能的程序設計。先看標準的銷售合同單據界面:html
本篇經過銷售合同單據功能,依次講解編程要點,供參考。編程
窗體有二種狀態,一種是編輯狀態,別一種是數據瀏覽狀態,區別在於編輯狀態的窗體數據被修改(dirty),在窗體關閉時須要保存數據。點擊工具條的新增(Insert)按鈕,窗體進入編輯狀態。新增狀態須要對窗體所編輯的單據設置默認值。通常咱們在實體映射文件中設置默認值,參考下面的例子代碼:ide
public partial class SalesContractEntity { protected override void OnInitialized() { base.OnInitialized(); // Assign default value for new entity if (Fields.State == EntityState.New) { #region DefaultValue // __LLBLGENPRO_USER_CODE_REGION_START DefaultValue this.Fields[(int) SalesContractFieldIndex.Closed].CurrentValue = false; // __LLBLGENPRO_USER_CODE_REGION_END #endregion } } }
也能夠考慮在窗體中作默認值設定。當遇到這樣一種場景,兩個功能對應同一個實體類型,則須要在界面中根據須要初始化值,參考下面的程序片斷。工具
protected override EntityBase2 Add() { base.Add(); this._inventoryMovement = new InventoryMovementEntity(); this._inventoryMovement.TranType = GetStringValue(InventoryTransactionType.Movement); return this._inventoryMovement; }
窗體基類檢測到界面中的控件值被修改過,窗體狀態變爲編輯狀態,點擊保存按鈕執行保存方法。保存方法的主要內容是將數據源控件(BindingSource)所綁定的控件值更新到它映射的實體中,再調用窗體保存方法保存實體。ui
protected override EntityBase2 Save(EntityBase2 entityToSave, EntityCollection entitiesToDelete) { SalesContractEntity SalesContractEntity = (SalesContractEntity)entityToSave; this._salesContractEntity = this._salesContractEntityManager.SaveSalesContract( SalesContractEntity, entitiesToDelete, SeriesCode); return this._salesContractEntity; }
entityToSave是數據源控件綁定的實體類型,在保存完成後,這個值再次綁定到數據源控件中。this
窗體只有在瀏覽狀態時,才能夠點擊刪除按鈕,刪除按鈕的內容是獲取窗體數據源控件綁定的實體,調用窗體刪除方法。spa
protected override void Delete(EntityBase2 entityToDelete) { base.Delete(entityToDelete); SalesContractEntity SalesContractEntity = (SalesContractEntity)entityToDelete; this._salesContractEntityManager.DeleteSalesContract(SalesContractEntity); }
對實體的任何操做,都會跑實體驗證類型,好比在保存時,須要驗證主鍵值是否已經保存過,參考下面的代碼。線程
public override void ValidateEntityBeforeSave(IEntityCore involvedEntity) { base.ValidateEntityBeforeSave(involvedEntity); SalesContractEntity salesContract = (SalesContractEntity)involvedEntity;
if (string.IsNullOrEmpty(salesContract.ContractNo)) throw new EntityValidationException("Contract No. is required"); if (string.IsNullOrEmpty(salesContract.CustomerNo)) throw new EntityValidationException("Customer No. is required"); if (salesContract.IsNew) { ISalesContractManager salesContractManager = CreateProxyInstance<ISalesContractManager>(); if (salesContractManager.IsSalesContractExist(salesContract.ContractNo)) throw new RecordDuplicatedException(salesContract.ContractNo, "Cotract No. is already used"); } }
窗體支持兩種複製方法,複製當前加載的值,複製其它對象的值。對象值複製完成後,需用重置新的對象的主鍵值,讓它爲空或是爲默認值,供用戶修改。複製其它對象的值須要彈出對象選擇窗體。這兩種複製都須要注意複製完後,重置對象初始化默認值。由於複製時採用的是深拷貝,沒有跑對象初始化值。翻譯
protected override object Clone(Dictionary<string, string> refNo) { base.Clone(refNo); string receiptRefNo; refNo.TryGetValue("ContractNo", out receiptRefNo); if (string.IsNullOrEmpty(receiptRefNo)) { using (ILookupForm lookup = GetLookupForm("SalesContractLookup")) { if (!AllowViewAllTransaction) lookup.PredicateBucket = new RelationPredicateBucket(SalesContractFields.CreatedBy == Shared.CurrentUser.UserId); lookup.SetCurrentValue(CurrentRefNo); if (lookup.ShowDialog() != DialogResult.OK)
return null; receiptRefNo = lookup.GetFirstSelectionValue(); } } if (!string.IsNullOrEmpty(receiptRefNo)) { this._salesContractEntity = this._salesContractEntityManager.CloneSalesContract(receiptRefNo); return this._salesContractEntity; } return null;
}
注意到這些方法所有是以override重寫的方式出現,被基類調用。每一個方法都運行在後臺線程控件BackgroundWorker線程中,因此都不能操做界面控件。設計
主要用於工具條的前四個按鈕,分別對應第一筆數據,前一筆數據,下一筆數據,最後一筆數據。工具條瀏覽須要設定窗體的NavigateBindingSource屬性,傳入一個空白的BindingSource控件或是一個裝載頁面全部數據的BindingSource控件,工具條瀏覽方法重寫參考下面的程序片斷。
protected override void InitNavigator(InitNavigatorArgs args) { base.InitNavigator(args); args.SortExpression.Add(SalesContractFields.ContractNo | SortOperator.Ascending); args.PredicateBucket.PredicateExpression.Add(SalesContractFields.Closed == false); }
主要用於業務單據過賬邏輯,基類的方法爲空方法,不一樣的業務單據有不一樣的邏輯定義,沒有可複用的代碼。
protected override void Post(EntityBase2 entityToPost) { base.Post(entityToPost); SalesContractEntity resignEntity = entityToPost as SalesContractEntity; _salesContractEntityManager.PostSalesContract(resignEntity); }
這裏的過賬能夠理解爲確認,批覈,不可更改的意思。在有些系統中叫送審,審覈。
通常在設計視圖綁定當前窗體對應的水晶報表文件以及要傳入的參數。也能夠經過重寫打印方法傳入傳數值。
protected override void Print(ref Dictionary<string, SelectionFormula> selectionFormulas, ref List<FormulaField> formulaFields, ref List<ParameterField> parameterFields) { base.Print(ref selectionFormulas, ref formulaFields, ref parameterFields); }
重寫方法經常使用於動態指定報表文件,或是動態的參數值。不推薦在代碼中這樣寫,這樣作致使每次都須要從新編譯和分發程序,推薦在水晶報表中作公式,在分發時只須要拷貝文件便可。