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