如何設(shè)計一個編輯窗體的基類
為什么我們需要一個編輯的基類呢?
我們發(fā)現(xiàn)對于編輯窗體而言,它們的工作基本的流程是大同小異,而且編輯窗體中每次都需要增加按鍵處理、是否有編輯內(nèi)容未保存等提示,因此我們需要一個基類來把這些基本的事情完成。
下面,我們看看是如何實(shí)現(xiàn)這個基類的。
通用界面與基本的流程
通用的界面
我們的編輯界面通常是在一個列表界面中,通過點(diǎn)擊添加或者編輯按鈕,打開一個編輯窗體,他們通常長成下面的這個樣子:
基本的流程
我們總結(jié)一下基本的流程是下面這樣的:
基類的基本實(shí)現(xiàn)
構(gòu)造函數(shù)
- public EditFormBase(){ ModelBound = false; _skipDefaultProcessCmdKey = false; AutoRename = true;
- InitializeComponent(); Activated += EditFormBase_Activated; StartPosition = FormStartPosition.CenterScreen;}
- public EditFormBase(IListFormBase listFrm) : this(){ ListForm = listFrm;}
- 其要點(diǎn)如下:
-
ModelBound
:在窗體編輯時有效,知識是否加載了數(shù)據(jù)庫中的Model,因為很多時候,我們的控件是有相關(guān)聯(lián)動而產(chǎn)生另外的數(shù)據(jù)的,有時候在數(shù)據(jù)綁定的時候并不想要產(chǎn)生這些事件,這個時候這個屬性就非常有用。比如收款金額,可能是**體積單價*體積**,但是也可能是錄單人員手動輸入的,這個時候,我們保存的內(nèi)容包括:體積單價、體積、收款金額;而編輯的時候,這個自動計算的功能是不需要的。 -
_skipDefaultProcessCmdKey
:是否忽略現(xiàn)有的鍵盤按鍵的操作。基類中我重寫了鍵盤按鍵事件,按ESC
關(guān)閉窗體,按Enter
提交表單。 -
AutoRename
:是否允許基類自動對窗體進(jìn)行命名。假設(shè)實(shí)現(xiàn)類中的Title
寫為“發(fā)貨單”,那么,新增時基類自動命名為“新增發(fā)貨單”;編輯時自動命名為“編輯發(fā)貨單”。 -
EditFormBase_Activated
:在這個事件中才處理Model
的綁定,這樣可以確保Model
的綁定在Form_Load
事件之后。 -
IListFormBase listFrm
:列表界面接口。這個接口要求列表界面對列表數(shù)據(jù)進(jìn)行刷新,這樣,我們在編輯和更新時候,就可以同時更新列表的數(shù)據(jù)了。因此,列表窗體必須實(shí)現(xiàn)這個接口。
窗體加載與激活
- ///窗體加載
- private void EditFormBase_Load(object sender, EventArgs e)
- {
- if (IsEdit)
- {
- if (AutoRename)
- Text = "編輯" + Text;
- }
- else
- {
- ModelBound = true;
- if (AutoRename)
- Text = "添加" + Text;
- }
- }
- ///窗體激活
- private void EditFormBase_Activated(object sender, EventArgs e)
- {
- if (!FormLoaded)
- {
- if (IsEdit)
- {
- BindEntity();
- ModelBound = true;
- AfterBindEntity();
- }
- FormLoaded = true;
- }
- }
提交表單
- //提交操作,一般在點(diǎn)擊按鈕之后觸發(fā)
- protected void ReadySaveEntity(bool close)
- {
- if (CheckInput())
- {
- Cursor = Cursors.WaitCursor;
- string operation = IsEdit ? "編輯" : "添加";
- try
- {
- if (SaveOrUpdateEntity(IsEdit))
- {
- MessageBoxHelper.ShowTipsSlide("{0}成功!!!", operation);
- RefreshUi();
- if (close)
- {
- DialogResult = DialogResult.OK;
- Close();
- }
- else
- {
- ClearScreen();
- }
- }
- }
- catch (Exception ex)
- {
- OnSaveOrUpdateError(ex, operation);
- }
- finally
- {
- Cursor = Cursors.Default;
- }
- }
- }
- //實(shí)際的提交,是一個虛方法,需要子類實(shí)現(xiàn),沒有實(shí)現(xiàn)將會彈出警告框
- protected virtual bool SaveOrUpdateEntity(bool isEdit)
- {
- MessageBoxHelper.ShowTips("沒有實(shí)現(xiàn)添加或者編輯記錄的接口,請與開發(fā)人員聯(lián)系");
- return false;
- }
列表更新與界面清空
- //都是有默認(rèn)的實(shí)現(xiàn),當(dāng)然你可以可以自己重寫
- protected virtual void RefreshUi()
- {
- if (ListForm != null)
- {
- ListForm.RefreshListView("");
- }
- else
- {
- MessageBoxHelper.ShowTips("沒有實(shí)現(xiàn)刷新界面的接口,請與開發(fā)人員聯(lián)系");
- }
- }
數(shù)據(jù)綁定、控件驗證
- //都是空方法,需要子類實(shí)現(xiàn)
- protected virtual void BindEntity()
- {
- }
- protected virtual void AfterBindEntity()
- {
- }
使用實(shí)例
以下面的界面為例子,我們講講如何實(shí)現(xiàn)這個編輯窗體
其基本實(shí)現(xiàn)步驟如下:
繼承基類
- public partial class SendOrderEdit : EditFormBase
- {
- public SendOrderEdit(IListFormBase list)
- : base(list)
- {
- InitializeComponent();
- }
- }
觸發(fā)保存并新增、保存并關(guān)閉按鈕
- //保存并新增
- private void btnSaveAndAdd_Click(object sender, EventArgs e)
- {
- ReadySaveEntity(false);
- IsEdit = false;
- }
- //保存并關(guān)閉
- private void btnSaveAndClose_Click(object sender, EventArgs e)
- {
- ReadySaveEntity(true);
- }
實(shí)現(xiàn)基本的操作流程
-
驗證
CheckInput
-
數(shù)據(jù)綁定
BindEntity
-
提交數(shù)據(jù)庫
SaveOrUpdateEntity
-
清空界面
ClearScreen
-
如果需要控制刷新列表的參數(shù),需要重寫刷新方法
RefreshUi
。
帶保存按鈕和關(guān)閉按鈕的基類
為了更簡化我們的操作和統(tǒng)一編輯界面,我們同時提供了下面這個編輯窗體基類,是帶有保存按鈕和關(guān)閉按鈕的:
它的實(shí)現(xiàn)非常簡單:
- public partial class BaseFormEditNew : EditFormBase
- {
- public BaseFormEditNew()
- {
- InitializeComponent();
- }
- public BaseFormEditNew(IListFormBase list)
- : base(list)
- {
- InitializeComponent();
- }
- private void btnCancel_Click(object sender, EventArgs e)
- {
- Close();
- }
- private void btnSave_Click(object sender, EventArgs e)
- {
- ReadySaveEntity(true);
- }
- }