為什么我們需要一個編輯的基類呢?
我們發現對於編輯窗體而言,它們的工作基本的流程是大同小異,而且編輯窗體中每次都需要增加按鍵處理、是否有編輯內容未保存等提示,因此我們需要一個基類來把這些基本的事情完成。
下面,我們看看是如何實現這個基類的。
通用界面與基本的流程
通用的界面
我們的編輯界面通常是在一個列表界面中,通過點擊添加或者編輯按鈕,打開一個編輯窗體,他們通常長成下面的這個樣子:
基本的流程
我們總結一下基本的流程是下面這樣的:
基類的基本實現
構造函數
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);
}
}