資訊化基礎建設 表單開發

來源:互聯網
上載者:User

表單開發的主題內容

1. 表單內容設定

2. CRUD與代碼產生

3. 進階選項

4. 設計規範

 

使用EPN架構製作員工主檔表單,如下

 屬性設定

增加表單,EmployeeMaster

設定繼承的類為EntryForm

[FunctionCode("SAISEM")]

public partial class EmployeeMaster : EntryForm

{

     public EmployeeMaster()

   {

     InitializeComponent();

    }

}

並且添加功能編碼SAISEM

在EPN的分類設定選項中,設定表單的EPN屬性如下

這表示,表單支援新增,修改,刪除,拷貝,匯入/匯出,過帳,增加附件,不支援批核(工作流程)

拖動一個EntityCollection到表單中,並設定它的EntityFactoryToUse對象

依照需要展示的資料層次結構,拖動為數個BindingSource到表單中。

舉例:比如要顯示採購單頭和採購明細資訊,需要拖動2個BindingSource,分別顯示採購單頭和採購明細

對於本例,需要顯示員工表的表頭資訊和檔案(Document)資訊,則需要拖動2個BindingSource

組件視窗看起來是這樣

然後依次設定BindingSource的資料來源

設定employeeBindingSource的資料來源

設定employeeDocumentBindingSource的資料來源

依據需要顯示的欄位,放表單中拖放TextEditor,NumberiEditor,Grid,CheckBox

在Visual Studio 2010中,看起來是這樣

設定表單的資料來源屬性,MainBindingSource和NavigateBindingSource

如果當前表單要一次性將所有的Entity讀入到表單的GridView,則將Form的MainBindingSource與navigatorBindingSource都設定為employeeBindingSource。

如果表單開啟時只需顯示一條Entity,則將表單的MainBindingSource設為employeeBindingSource,再添加一個新的bindingSource組件,資料來源不要選,留空。將其設為表單的NavigatorBindingSource。

設定表單主鍵屬性

設定值如下

至此,F5,表單已經可以運行,在快速啟動欄中輸入SAISEM,即可啟動表單,如開篇所展示的效果。

 代碼產生

到目前為止,表單已經可以運行,但並不可以進行資料的讀寫,我們還要給它新增加資料讀寫代碼。

再引用開發架構中關於庫存項目的一張圖

BusinessLogic 商務邏輯,業務實體,這個由代碼產生器自動產生

Interface 介面 讀寫資料和商務邏輯的介面

Manager 實現介面 實現介面

System Administration/Inventory, 介面,放入EmployeeMaster表單

為此,祭出代碼產生工具CodeSmith,幫忙我們完成枯燥容易出錯的應用程式框架的代碼。

介面檔案IEmployeeManager,將產生的檔案拷貝到Interface項目中

實現檔案EmployeeManager,將產生的檔案拷貝到Manager項目中

表單檔案產生,將產生的檔案內容拷貝到EmployeeMaster表單檔案中

代碼如下

private IEmployeeManager _EmployeeManager = null ;

private EmployeeEntity _Employee = null ;

protected override void OnShown(EventArgs e)

{

base.OnShown(e);

if (!DesignMode)

{

}

}

protected override void OnLoad(EventArgs e)

{

if(!DesignMode)

this._EmployeeManager = ClientProxyFactory.CreateProxyInstance<IEmployeeManager>();

base.OnLoad(e);

}

protected override void InitNavigator(InitNavigatorArgs args)

{

base.InitNavigator(args);

args.SortExpression.Add(EmployeeFields.EmployeeNo | SortOperator.Ascending);

}

protected override EntityBase2 LoadData(Dictionary<string, string> refNo)

{

base.LoadData(refNo);

string employeeNo = string.Empty;

if (refNo.TryGetValue("EmployeeNo", out employeeNo))

{

IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.EmployeeEntity);

prefetchPath.Add(EmployeeEntity.PrefetchPathEmployeeDocument);

_employee = _employeeManager.GetEmployee(employeeNo, prefetchPath);

}

else

{

_employee = new EmployeeEntity();

}

return _employee;

}

protected override void BindControls(EntityBase2 entity)

{

base.BindControls(entity);

this.employeeBindingSource.DataSource = entity;

}

protected override EntityBase2 Add( )

{

base.Add();

this._Employee = new EmployeeEntity();

return _Employee;

}

protected override EntityBase2 Save(EntityBase2 entityToSave)

{

base.Save(entityToSave);

EmployeeEntity _Employee = (EmployeeEntity)entityToSave;

this._Employee =this._EmployeeManager.SaveEmployee(_Employee);

return _Employee;

}

protected override void Delete(EntityBase2 entityToDelete)

{

base.Delete(entityToDelete);

EmployeeEntity Employee = (EmployeeEntity)entityToDelete;

this._EmployeeManager.DeleteEmployee(Employee);

}

protected override object Clone(Dictionary<string, string> refNo)

{

base.Clone(refNo);

string employeeNo = string.Empty;

refNo.TryGetValue("EmployeeNo", out employeeNo);

if (string.IsNullOrEmpty(employeeNo))

{

using (ILookupForm lookup = EPN.Common.GetLookupForm("EmployeeLookup"))

{

lookup.SetCurrentValue(CurrentRefNo);

if (lookup.ShowDialog() != DialogResult.OK)

return null;

employeeNo = lookup.GetFirstSelectionValue();

}

}

if (!string.IsNullOrEmpty(employeeNo))

{

this._employee = this._employeeManager.CloneEmployee(employeeNo);

return this._employee;

}

return null;

}

protected override void ReleaseResources( )

{

base.ReleaseResources();

try

{

_Employee = null;

_EmployeeManager= null;

}

catch

{

}

}

到此,已經完成了表單開發的所有內容。

為加入更多的驗證邏輯,產生一些驗證,放到驗證項目中

比如,需要驗證社會安全號碼碼必須輸入,電話號碼要符合當地的編號規則,等等,這些邏輯驗證,都可以寫在這裡

 進階選項

到此為止,幾乎是沒有敲任何的代碼,我們就完成了員工主檔的開發,這樣的速度,肯定讓你吃驚,也開始疑惑:

1. 商務邏輯寫在哪裡?

比如,當輸入員工的出生日期為1983年時,程式應當自動算出員工的年齡為DateTime.Now- DateTime(1983,10,20), 當輸入員工的學曆為本科時,它在公司的組織架構層級中,就自動對應22B,而不是大專畢業對應的21B。

參考一開始設計的圖,程式從一開始就是介面和邏輯分離的,邏輯直接寫到BusinessLogical項目中去,也就是代碼自動產生的EmployeeEntity檔案。

這裡有一個小技巧,代碼產生器會為我們產生2個EmployeeEntity檔案,一個是EmployeeEntity.cs, 另一個是EmployeeEntity.Logical.cs的檔案,前一個檔案,是依據資料表的欄位,自動產生的檔案,後一個檔案,是存放自訂邏輯的地方,也就是需要放入邏輯的代碼檔案。

2. 程式介面上的特殊要求,通過以上產生的程式碼肯定沒有做到。

比如,需要給員工主檔添加圖片顯示,中,顯示James Bond的圖片,這個功能需要手動寫。

其次,要給物料主檔添加條碼支援,將產生的條碼作為物料編碼的依據,這個功能也需要手寫。

再比如開篇中的那張圖片,Employee No.後面的按鈕,是用來給員工智能編碼用的。一般會依據員工學曆,工作經驗,專業的不同來產生相應的員工編碼。

3. 邏輯和介面嚴格分離帶來的一些問題。

如果要在邏輯裡面根據不同的條件,給使用者一個提示,這個會相當麻煩。因為邏輯與介面已經嚴格分離,絕不允許在邏輯中調用MessageBox.Show, 為了阻止這個行為的發生,在邏輯的References中,直接刪除了System.Windows.Forms的引用。

同理,在介面中訪問邏輯中的部分程式碼片段也相當麻煩,有時候在介面中也需要直接存取資料庫,比如,在做銷售送貨時,根據目前使用者輸入的銷售單號,判斷這個SO是否已經完成送貨,如果已經完成送貨,則不允許產生送貨單,這個邏輯只有在介面上實現,因為在BusinessLogical中Shipment對象還沒有產生,無法做判斷。

4. 效能 Performance

在把資料從資料庫讀到介面時,ORM和ADO.NET效能區別不大,但是,在做儲存和更新時,ORM會判斷當前已經做出修改的資料,僅僅產生這個被修改資料的UPDATE語句,這樣的效能提升是很佔優勢的。

ADO.NET中,更新員工的語句一般是

UPDATE Name=’James Bond’ , Country=’ England’ WHERE EmployeeNo=’007’

很少可能會這樣寫,為了更新員工的名字,寫一個SQL

UPDATE Name=’James Bond’ WHERE EmployeeNo=’007’

更新員工的國籍,於是又寫一個SQL

UPDATE Country=’ England’ WHERE EmployeeNo=’007’

ORM架構會很高興的幫忙我們判斷,究竟有哪些資料被修改(dirty),並且只產生這些資料的UPDATE.

 表單規範

CodeSmith已經幫忙我們做好了大量的重複代碼,也相當規範。

如果仍然要手寫代碼,遵守共同的規範,會使代碼看起來更統一,規範

控制項命名規範

控制項類型

首碼

舉例

Label  

lbl    

lblMessage

Button  

Btn

btnSave

GroupBox

gbx    

gbxMain

GridView

grd

grdSalesOrderDetails

僅有這個規範還不行,畢竟遵守起來還是有點困難,EPN架構還運用分詞技術,自動為表單中的控制項重新命名。

我們的表單中的控制項代碼,看起來是這樣

private EPN.WinUI.TextEditor txtDeptName;

private EPN.WinUI.Label lblDeptName;

private EPN.WinUI.PictureBox picImage;

private EPN.WinUI.GridView grdSalesOrder;

當為控制項綁定屬性時,自動為控制項重新命名。比如,我將TextBox1綁定到資料來源EmployeeNo,於是控制項被重新命名為txtEmployeNo,看控制項名稱,就可以知道資料來源,也知道控制項類型,以達到高度的規範統一。

 

表單的設計標準

1 DialogBox,對話方塊,一般要能響應ESC和Enter鍵,也有OK和Cancel2個按鈕

2 表單中控制項的Tab order是否合理

3 Short cut key,快鍵鍵訪問,所有的表單也需要一致,也不能有衝突。

4 當表單中需要盛放的資料量較大時,有2種思路

以GroupBox分組,以方便查看

當資料量再增多時,以Tab分組

5 表單執行時間較長的任務,要使BackgroundWorker,以保證表單可以接受響應,任務執行完畢後,或用MessageBox.Show顯示successfully done,或與VS2010一樣,在status bar中顯示執行結果.比如在VS2010中成功check in代碼後,在status bar中會顯示成功簽入變更集54498.

同時,cursor也不能放過,像這樣寫:

this.Cursor=Cursors.WaitCursor;

.....long operation

this.Cursor=Cursors.Default;

6 表單組織方式,避免MDI forms,推薦tab式 MDI。

必要時,可以這樣,把form放到panel中,設定form的TopLevel = false

7 ListView控制項,要支援copy,而且可以多行copy

8 Enter和Tab key的作用,都會去下一個tab order的control

9 WinForms程式,最好的可以接受command line的啟動方式,這樣可以用bat命令啟動。而且可以加啟動參數。

VS2005、2008,2010都可以從command line啟動。還記得常用的deven /resetpackage嗎?

10 盡量阻止一台電腦,同時運行程式的兩個執行個體,使用Singletion模式。

11 Target盡量是AnyCPU,而不x86。因為Microsoft Jet Access 資料庫沒有64bit的版本,寧願移除對Jet Access的依賴和使用,也不願把Target改成x86. 自Windows 7以來,64bit的OS已經相當普及,要使自己的程式不會一開啟就stop working,就盡量編譯成AnyCPU吧。

12 RichTextBox,如果是程式新增內容,需要auto scroll到最行的一行資料。觀察VS2010編譯的時候,Output視窗

13 對於使用者不能修改的資料,不僅要使TextBox為readonly,最好還要使它的背景顏色變成gray,一目瞭然。

必須輸入資料的控制項,需要有個統一的提示,像這樣

當該控制項有值時,右邊的紅色圖片hidden,沒有值時,顯示圖片。這和Ajax中的watermark是相同的原理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.