我們?cè)陂_發(fā)一些Winform程序的時(shí)候叙量,除了常規(guī)的顯示普通數(shù)據(jù)外,有的時(shí)候需要顯示一些人員肖像或者一些車輛等物體的圖片九串,一般這些內(nèi)容較小,所以以二進(jìn)制存儲(chǔ)在數(shù)據(jù)庫(kù)是一個(gè)不錯(cuò)的方案寺鸥。但由于它們雖然很常用猪钮,設(shè)計(jì)數(shù)據(jù)庫(kù)保存的邏輯又會(huì)使得整個(gè)控件的封裝顯得麻煩很多。本文介紹的肖像顯示保存控件胆建,通過事件的封裝處理烤低,讓數(shù)據(jù)的保存不在依賴于數(shù)據(jù)庫(kù)存儲(chǔ)模塊,實(shí)現(xiàn)更加通用的特性笆载。
1扑馁、肖像顯示保存控件的需求
我們?cè)谝恍┏绦蛄死锩妫赡苄枰@示一些人員頭像凉驻,車輛圖片腻要,物件圖片等,這些圖片可以從電腦上選取涝登,也可以拍照雄家,當(dāng)然最重要的是,方便使用胀滚,并能存儲(chǔ)到數(shù)據(jù)庫(kù)里面趟济,這個(gè)就是我們一般的需求了乱投。
1)人員肖像顯示效果:
2)車輛圖片展示效果
控件的工具條上,提供了編輯圖片顷编,保存圖片戚炫,恢復(fù)默認(rèn)圖片,拍照等功能媳纬,當(dāng)然我們希望控件和整個(gè)界面一起双肤,實(shí)現(xiàn)圖片數(shù)據(jù)的方便加載和保存操作。
2层宫、肖像顯示保存控件的設(shè)計(jì)
前面我們看了一些常用的場(chǎng)景杨伙,對(duì)我們?cè)O(shè)計(jì)這個(gè)通用性的肖像顯示保存控件有很好的指導(dǎo)意義,我們只需要把圖片顯示部分作為一個(gè)控件萌腿,然后公布一些事件給外部實(shí)現(xiàn)限匣,從而實(shí)現(xiàn)我們需要的數(shù)據(jù)加載、數(shù)據(jù)保存等操作毁菱,至于其他的功能米死,我們可以集成到里面去。
我們?cè)O(shè)計(jì)一個(gè)用戶自定義控件贮庞,上面放一個(gè)圖片顯示框峦筒,然后增加一些按鈕在上面,并設(shè)置好工具欄的圖片顯示窗慎,效果如下所示物喷。
由于我們需要給外部處理數(shù)據(jù)的綁定(需要從數(shù)據(jù)庫(kù)加載)和數(shù)據(jù)的保存(保存到數(shù)據(jù)庫(kù)里面),因此拋出兩個(gè)委托代理定義遮斥。
/// <summary>
/// 保存圖片的處理代理定義
/// </summary>
/// <param name="id">記錄ID</param>
/// <param name="imageBytes">圖片數(shù)據(jù)</param>
/// <param name="imageType">圖片類型</param>
/// <returns></returns>
public delegate bool SavePortraitHandler(string id, byte[] imageBytes, string imageType);
/// <summary>
/// 綁定圖片數(shù)據(jù)的代理定義
/// </summary>
/// <param name="id">記錄ID</param>
/// <param name="imageType">圖片類型</param>
/// <returns></returns>
public delegate byte[] BindPortraitHandler(string id, string imageType);
然后我們?cè)谟脩艨丶锩嬖黾右恍傩院褪录x峦失,部分代碼如下所示。
/// <summary>
/// 圖片數(shù)據(jù)顯示和采集控件
/// </summary>
public partial class PortraitControl : XtraUserControl
{
#region 事件及屬性定義
/// <summary>
/// 保存圖片操作的事件
/// </summary>
public event SavePortraitHandler OnSavePortrait;
/// <summary>
/// 綁定圖片數(shù)據(jù)的事件
/// </summary>
public event BindPortraitHandler OnBindPortait;
/// <summary>
/// 記錄ID
/// </summary>
public string ID { get; set; }
/// <summary>
/// 圖片是否被修改過
/// </summary>
public bool ImageIsDirty { get; set; }
然后我們需要實(shí)現(xiàn)的就是术吗,公布兩個(gè)公共方法尉辑,分別是數(shù)據(jù)的綁定,綁定到界面控件的操作函數(shù)较屿,我們主要注意的是隧魄,這里調(diào)用了事件OnBindPortait,以實(shí)現(xiàn)數(shù)據(jù)庫(kù)的解耦隘蝎,代碼如下所示购啄。
/// <summary>
/// 綁定圖片的操作,觸發(fā)綁定事件處理
/// </summary>
/// <param name="id">記錄ID</param>
public void BindPicture(string id)
{
try
{
this.ID = id; //設(shè)置控件的ID值
#region 更新圖片顯示操作
if (OnBindPortait == null)
{
MessageDxUtil.ShowTips("控件未指定OnBindPortait事件處理");
return;
}
byte[] imageBytes = OnBindPortait(id, ImageType);
if (imageBytes != null)
{
this.picPortrait.Image = ImageHelper.ImageFromBytes(imageBytes);
}
else
{
ResetDefaultImage(ImageType);
}
#endregion
}
catch (Exception ex)
{
MessageDxUtil.ShowError(ex.Message);
LogTextHelper.Error(ex);
}
}
數(shù)據(jù)庫(kù)保存的實(shí)現(xiàn)末贾,和上面思路差不多闸溃,也是實(shí)現(xiàn)事件的處理即可,通過調(diào)用事件OnSavePortrait,實(shí)現(xiàn)數(shù)據(jù)庫(kù)的解耦辉川。
/// <summary>
/// 保存圖片到服務(wù)器
/// </summary>
public bool SavePicture(string id)
{
this.ID = id;//設(shè)置控件的ID值
if (string.IsNullOrEmpty(id))
{
MessageDxUtil.ShowTips("記錄ID未指定表蝙,無(wú)法保存,請(qǐng)先保存數(shù)據(jù)乓旗!");
return false;
}
if (OnSavePortrait == null)
{
MessageDxUtil.ShowTips("控件未指定OnSavePortrait處理事件府蛇!");
return false;
}
if (picPortrait.Image != null)
{
try
{
byte[] imageBytes = ImageHelper.ImageToBytes(this.picPortrait.Image);
bool sucess = false;
if (OnSavePortrait != null)
{
sucess = OnSavePortrait(this.ID, imageBytes, ImageType);
}
return sucess;
}
catch (Exception ex)
{
MessageDxUtil.ShowError(ex.Message);
LogTextHelper.Error(ex);
}
}
return false;
}
3、肖像顯示保存控件的使用
完成以上控件的設(shè)計(jì)和處理后屿愚,編譯后汇跨,模塊將增加一個(gè)用戶控件,這樣我們就可以在需要的界面模塊里面妆距,把這個(gè)控件拖動(dòng)到設(shè)計(jì)界面里面去了穷遂,設(shè)計(jì)效果和下圖類似。
這個(gè)時(shí)候娱据,肖像顯示保存控件就作為一個(gè)整體進(jìn)行使用了蚪黑。
由于我們?cè)O(shè)計(jì)控件的時(shí)候,我們把它和外部數(shù)據(jù)庫(kù)存儲(chǔ)和加載進(jìn)行了隔離中剩,因此這里需要進(jìn)行整合忌穿,通過事件進(jìn)行整合處理。調(diào)用代碼如下所示结啼。
public partial class FrmEditDriver : BaseEditForm
{
public FrmEditDriver()
{
InitializeComponent();
this.portraitControl1.ImageType = "個(gè)人肖像";
this.portraitControl1.OnBindPortait += new BindPortraitHandler(portraitControl1_OnBindPortait);
this.portraitControl1.OnSavePortrait += new SavePortraitHandler(portraitControl1_OnSavePortrait);
}
然后實(shí)現(xiàn)其中自動(dòng)增加的事件函數(shù)即可掠剑,主要就是調(diào)用業(yè)務(wù)類實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ)和加載處理邏輯,代碼如下所示郊愧。
bool portraitControl1_OnSavePortrait(string id, byte[] imageBytes, string imageType)
{
return BLLFactory<Driver>.Instance.UpdateImageBytes(id, imageBytes, imageType);
}
byte[] portraitControl1_OnBindPortait(string id, string imageType)
{
return BLLFactory<Driver>.Instance.GetImageBytes(id, imageType);
}
在數(shù)據(jù)的顯示函數(shù)里面朴译,我們主動(dòng)調(diào)用控件的函數(shù)實(shí)現(xiàn)界面數(shù)據(jù)的綁定顯示。
/// <summary>
/// 數(shù)據(jù)顯示的函數(shù)
/// </summary>
public override void DisplayData()
{
InitDictItem();//數(shù)據(jù)字典加載(公用)
if (!string.IsNullOrEmpty(ID))
{
#region 顯示信息
DriverInfo info = BLLFactory<Driver>.Instance.FindByID(ID);
if (info != null)
{
tempInfo = info;//重新給臨時(shí)對(duì)象賦值属铁,使之指向存在的記錄對(duì)象
txtHandNo.Text = info.HandNo;
txtName.Text = info.Name;
txtMobile.Text = info.Mobile;
txtDept.Text = info.Dept;
txtStartDriveDate.SetDateTime(info.StartDriveDate);
txtSex.Text = info.Sex;
txtBirthday.SetDateTime(info.Birthday);
txtNote.Text = info.Note;
}
#endregion
}
else
{
}
//綁定圖片
this.portraitControl1.BindPicture(tempInfo.ID);
}
而在保存按鈕實(shí)現(xiàn)數(shù)據(jù)保存的時(shí)候动分,我們也可以調(diào)用控件自身的保存操作函數(shù),實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ)红选。
/// <summary>
/// 新增狀態(tài)下的數(shù)據(jù)保存
/// </summary>
/// <returns></returns>
public override bool SaveAddNew()
{
DriverInfo info = tempInfo;//必須使用存在的局部變量,因?yàn)椴糠中畔⒖赡鼙桓郊褂? SetInfo(info);
try
{
#region 新增數(shù)據(jù)
bool succeed = BLLFactory<Driver>.Instance.Insert(info);
if (succeed)
{
//可添加其他關(guān)聯(lián)操作
this.portraitControl1.SavePicture(tempInfo.ID);
return true;
}
#endregion
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
MessageDxUtil.ShowError(ex.Message);
}
return false;
}
通過和數(shù)據(jù)庫(kù)操作實(shí)現(xiàn)解耦姆另,我們可以對(duì)這個(gè)控件進(jìn)行更方便的重用喇肋,而代碼也很簡(jiǎn)單,這樣也就實(shí)現(xiàn)了我們統(tǒng)一化迹辐、簡(jiǎn)單化蝶防、可復(fù)用性的目標(biāo)了。