我們在開發Winform程序的時候,需要經常性的對界面的一些控件進行初始化,或者經常簡單的封裝,以方便我們在界面設計過程中反復使用。本文主要介紹在我的一些項目中經常性的界面處理操作和代碼,以便為大家開發的時候提供必要的參考。
1、選擇用戶的控件封裝操作
在一些系統模塊里面,我們需要選擇系統人員作為經辦人員的操作,如下面幾個界面場景所示。
我們注意到,一般在我們選擇的時候,界面會彈出一個新的層給我們選擇,里面通過列表詳細展示相關的信息,還可以支持搜索,非常方便。
當我們完成選擇的時候,我們看到界面會只有一個人員名稱的顯示,不占用額外的地方顯示。
這種界面效果是如何實現的呢?下面進行詳細的介紹。
1)首先我們定義一個自定義控件,讓其繼承自XtraUserControl 即可。
/// <summary> /// 經辦人員、操作人員的選擇控件封裝 /// </summary> public partial class OperatorSelectControl : XtraUserControl {
2)然后在DevExpress的界面工具箱上拖動一個SearchLookUpEdit 控件到我們新的用戶控件OperatorSelectControl 上。
調整好用戶界面控件的排版相關屬性,就會得到下面的界面所示。
3)在設計視圖里面,我們為這個SearchLookUpEdit控件的GridView設置它的顯示字段,如下所示,每個字段主要綁定FieldName(屬性或者字段)和Caption(顯示名稱)。
這些必備的處理操作完成后,我們可以通過代碼或者設計器把這個控件的顯示內容和存儲內容進行設定,並綁定它的數據源即可(根據需要調用自己的函數),如下所示。
private void OperatorSelectControl_Load(object sender, EventArgs e) { if (!this.DesignMode) { txtOperator.Properties.ValueMember = "ID"; txtOperator.Properties.DisplayMember = "FullName"; txtOperator.Properties.DataSource = SecurityHelper.GetSimpleUsers(); } }
4)我們為了方便,還可以進一步處理控件的顯示內容和返回的值內容,我們希望綁定值或者獲取值的時候,使用Text屬性就可以了,那么我們重載一下這個自定義控件的Text屬性即可。
public override string Text { get { string result = ""; if (this.txtOperator.EditValue != null) { result = this.txtOperator.EditValue.ToString(); } return result; } set { this.txtOperator.EditValue = value; } }
5)這樣控件的操作就完成了,編譯代碼后,我們在工具箱上就可以看到最新的控件圖標了。
接着我們把相關的控件拖動到需要的地方(如果是界面和控件在相同的工程里面,注意需要移除重復的工程引用),重新編譯系統代碼,那么本文開始的界面效果就可以出現了。
2、會員卡級別選擇操作
剛才說了,人員選擇可以使用這種彈出列表選擇的方式,其實很多地方可以用這個方式來進行選擇,如一些相對比較少記錄的信息就很適合這種顯示方式,比如在會員管理里面的,會員卡級別的選擇,也可以采用這種方式。
這個模塊的做法也和第一種很類似,有點不同的是,我需要選擇后把會員卡的折扣也關聯顯示出來,那我們應該如何處理呢?
1)定義控件和事件處理
為了方便在控件選擇后進行事件的觸發處理,我在這里定義了一個事件處理器SelectedValueChanged
/// <summary> /// 卡級選擇控件 /// </summary> public partial class CardGradeSelectControl : XtraUserControl { /// <summary> /// 選擇項發生變化的事件處理 /// </summary> public event EventHandler SelectedValueChanged;
然后在內部控件的EditValue改變的時候,在其中的事件里面觸發我們自定義的事件即可, 如下所示。
private void txtCardGrade_EditValueChanged(object sender, EventArgs e) { if (SelectedValueChanged != null) { SelectedValueChanged(sender, e); } }
2)在窗體界面中自定義控件的事件調用
在會員編輯界面里面,我們對這個卡級別的選擇控件的自定義事件進行處理即可。
處理事件里面,我們獲取對應卡級別的優惠折扣(GetDiscountByGradeNo),然后綁定到界面的控件顯示即可,這樣就實現了聯動效果了。
public partial class FrmEditMember : BaseEditForm { /// <summary> /// 創建一個臨時對象,方便在附件管理中獲取存在的GUID /// </summary> private MemberInfo tempInfo = new MemberInfo(); public FrmEditMember() { InitializeComponent(); this.txtCardGrade.SelectedValueChanged += new EventHandler(txtCardGrade_SelectedValueChanged); } void txtCardGrade_SelectedValueChanged(object sender, EventArgs e) { string gradeNo = txtCardGrade.Text; if (!string.IsNullOrEmpty(gradeNo)) { this.txtDiscount.Value = BLLFactory<CardGrade>.Instance.GetDiscountByGradeNo(gradeNo); } }
3、創建人員和創建時間的顯示處理
在我們窗體數據的編輯界面里面,為了友好顯示,我們可能需要顯示數據的創建人和創建時間。這種效果是如何實現的,我們來看看。
1)數據顯示時候處理
數據顯示的時候,可能是新增界面的顯示,也可以是現有記錄的顯示,我們需要區分對待。
如果是已有數據,我們需要解析創建人員的ID,顯示已有時間即可;如果是新增界面,那么我們把當前登陸用戶的名稱顯示出來,及顯示當前時間即可。
在設計模式里面,把控件設置為ReadOnly=true,不用編輯修改控件的值即可。
/// <summary> /// 數據顯示的函數 /// </summary> public override void DisplayData() { InitDictItem();//數據字典加載(公用) if (!string.IsNullOrEmpty(ID)) { #region 顯示信息 MemberInfo info = BLLFactory<WHC.Member.BLL.Member>.Instance.FindByID(ID); if (info != null) { tempInfo = info;//重新給臨時對象賦值,使之指向存在的記錄對象 txtHandNo.Text = info.HandNo; txtCardNo.Text = info.CardNo; txtCardCode.Text = info.CardCode; txtCardStatus.SetComboBoxItem(info.CardStatus.ToString()); txtOpenUser.Text = info.OpenUser;
.............. txtCreator.Text = SecurityHelper.GetFullNameByID(info.Creator); txtCreateTime.SetDateTime(info.CreateTime); } #endregion } else {this.txtOpenDate.DateTime = DateTime.Now; this.txtHandNo.Text = IDUtils.NewId(); this.txtCreateTime.DateTime = DateTime.Now; this.txtCreator.Text = LoginUserInfo.FullName;//默認為當前登錄用戶 } this.portraitControl1.MemberID = tempInfo.ID; this.portraitControl1.BindPicture(tempInfo.ID); //tempInfo在對象存在則為指定對象,新建則是全新的對象,但有一些初始化的GUID用於附件上傳 SetAttachInfo(tempInfo); }
但用戶保存操作的時候,如果是新增數據,我們需要把當前時間和當前用戶的信息記錄到數據庫里面,因此需要增加一些代碼進行數據的關聯處理。
/// <summary> /// 新增狀態下的數據保存 /// </summary> /// <returns></returns> public override bool SaveAddNew() { MemberInfo info = tempInfo;//必須使用存在的局部變量,因為部分信息可能被附件使用 SetInfo(info); info.Creator = LoginUserInfo.ID.ToString(); info.CreateTime = DateTime.Now; info.Dept_ID = LoginUserInfo.DeptId; info.Company_ID = LoginUserInfo.CompanyId; try { #region 新增數據 //檢查是否還有其他相同關鍵字的記錄 bool exist = BLLFactory<WHC.Member.BLL.Member>.Instance.IsExistKey("CardNo", info.CardNo); if (exist) { MessageDxUtil.ShowTips("指定的【會員卡號】已經存在,不能重復添加,請修改"); return false; } bool succeed = BLLFactory<WHC.Member.BLL.Member>.Instance.Insert(info); if (succeed) { //可添加其他關聯操作 return true; } #endregion } catch (Exception ex) { LogTextHelper.Error(ex); MessageDxUtil.ShowError(ex.Message); } return false; }
我們為了方便,一般是在數據庫存儲人員的ID,但是列表顯示的時候,我們也就需要把對應的人員ID轉換為人員名稱了。
this.winGridViewPager1.gridView1.CustomColumnDisplayText += new DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventHandler(gridView1_CustomColumnDisplayText);
void gridView1_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e) { if (e.Column.FieldName == "Operator" || e.Column.FieldName == "Editor" || e.Column.FieldName == "Creator") { if (e.Value != null) { e.DisplayText = SecurityHelper.GetFullNameByID(e.Value.ToString()); } } }